5 angular.module('egVolCopy',
6 ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod', 'egGridMod'])
8 .filter('boolText', function(){
14 .config(function($routeProvider, $locationProvider, $compileProvider) {
15 $locationProvider.html5Mode(true);
16 $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); // grid export
19 delay : ['egStartup', function(egStartup) { return egStartup.go(); }]
22 $routeProvider.when('/cat/volcopy/:dataKey', {
23 templateUrl: './cat/volcopy/t_view',
24 controller: 'EditCtrl',
32 function(egCore , $q) {
35 tree : {}, // holds lib->cn->copy hash stack
36 copies : [] // raw copy list
39 // returns a promise resolved with the list of circ mods
40 service.get_classifications = function() {
42 return $q.when(egCore.env.acnc.list);
44 return egCore.pcrud.retrieveAll('acnc', null, {atomic : true})
45 .then(function(list) {
46 egCore.env.absorbList(list, 'acnc');
51 service.get_prefixes = function(org) {
52 return egCore.pcrud.search('acnp',
53 {owning_lib : egCore.org.fullPath(org, true)},
59 service.get_locations = function(orgs) {
60 return egCore.pcrud.search('acpl',
66 service.get_suffixes = function(org) {
67 return egCore.pcrud.search('acns',
68 {owning_lib : egCore.org.fullPath(org, true)},
74 service.get_statuses = function() {
76 return $q.when(egCore.env.ccs.list);
78 return egCore.pcrud.retrieveAll('ccs', {}, {atomic : true}).then(
80 egCore.env.absorbList(list, 'ccs');
87 service.get_circ_mods = function() {
89 return $q.when(egCore.env.ccm.list);
91 return egCore.pcrud.retrieveAll('ccm', {}, {atomic : true}).then(
93 egCore.env.absorbList(list, 'ccm');
100 service.get_circ_types = function() {
102 return $q.when(egCore.env.citm.list);
104 return egCore.pcrud.retrieveAll('citm', {}, {atomic : true}).then(
106 egCore.env.absorbList(list, 'citm');
113 service.get_age_protects = function() {
114 if (egCore.env.crahp)
115 return $q.when(egCore.env.crahp.list);
117 return egCore.pcrud.retrieveAll('crahp', {}, {atomic : true}).then(
119 egCore.env.absorbList(list, 'crahp');
126 service.bmp_parts = {};
127 service.get_parts = function(rec) {
128 if (service.bmp_parts[rec])
129 return $q.when(service.bmp_parts[rec]);
131 return egCore.pcrud.search('bmp',
133 null, {atomic : true}
134 ).then(function(list) {
135 service.bmp_parts[rec] = list;
144 acp : ['call_number','parts'],
145 acn : ['label_class','prefix','suffix']
149 service.addCopy = function (cp) {
151 if (!cp.parts()) cp.parts([]); // just in case...
153 var lib = cp.call_number().owning_lib();
154 var cn = cp.call_number().id();
156 if (!service.tree[lib]) service.tree[lib] = {};
157 if (!service.tree[lib][cn]) service.tree[lib][cn] = [];
159 service.tree[lib][cn].push(cp);
160 service.copies.push(cp);
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,
168 service.addCopy(copy);
176 .directive("egVolCopyEdit", function () {
182 '<div class="col-xs-6"><input type="text" ng-model="barcode" ng-change="updateBarcode()"/></div>'+
183 '<div class="col-xs-2"><input type="number" ng-model="copy_number" ng-change="updateCopyNo()"/></div>'+
184 '<div class="col-xs-4"><eg-basic-combo-box list="parts" selected="part"></eg-basic-combo-box></div>'+
187 scope: { copy: "=", callNumber: "=" },
188 controller : ['$scope','itemSvc',
189 function ( $scope , itemSvc ) {
190 $scope.new_part_id = 0;
192 $scope.updateBarcode = function () { $scope.copy.barcode($scope.barcode); $scope.copy.ischanged(1); };
193 $scope.updateCopyNo = function () { $scope.copy.copy_number($scope.copy_number); $scope.copy.ischanged(1); };
194 $scope.updatePart = function () {
195 var p = $scope.part_list.filter(function (x) {
196 return x.label() == $scope.part
198 if (p.length > 0) { // preexisting part
200 } else { // create one...
201 var part = new egCore.idl.bmp();
202 part.id( --$scope.new_part_id );
204 part.label( $scope.part );
205 part.record( $scope.callNumber.owning_lib() );
206 $scope.copy.parts([part]);
207 $scope.copy.ischanged(1);
211 $scope.barcode = $scope.copy.barcode();
212 $scope.copy_number = $scope.copy.copy_number();
214 if ($scope.copy.parts()) {
215 $scope.part = $scope.copy.parts()[0];
216 if ($scope.part) $scope.part = $scope.part.label();
220 $scope.part_list = [];
222 itemSvc.get_parts($scope.callNumber.record()).then(function(list){
223 $scope.part_list = list;
224 angular.forEach(list, function(p){ $scope.parts.push(p.label()) });
233 .directive("egVolRow", function () {
240 '<div class="col-xs-1">'+
241 '<select ng-model="classification" ng-options="cl.name() for cl in classification_list track by idTracker(cl)"/>'+
243 '<div class="col-xs-1">'+
244 '<select ng-model="prefix" ng-change="updatePrefix()" ng-options="p.label() for p in prefix_list track by idTracker(p)"/>'+
246 '<div class="col-xs-3"><input type="text" ng-change="updateLabel()" ng-model="label"/></div>'+
247 '<div class="col-xs-1">'+
248 '<select ng-model="suffix" ng-change="updateSuffix()" ng-options="s.label() for s in suffix_list track by idTracker(s)"/>'+
250 '<div class="col-xs-1"><input type="number" ng-model="copy_count" min="{{orig_copy_count}}" ng-change="changeCPCount()"></div>'+
251 '<div class="col-xs-5">'+
252 '<div class="container-fluid">'+
253 '<eg-vol-copy-edit ng-repeat="cp in copies track by idTracker(cp)" copy="cp" call-number="callNumber"></eg-vol-copy-edit>'+
258 scope: {allcopies: "=", copies: "=" },
259 controller : ['$scope','itemSvc','egCore',
260 function ( $scope , itemSvc , egCore ) {
261 $scope.new_cp_id = 0;
262 $scope.callNumber = $scope.copies[0].call_number();
264 $scope.idTracker = function (x) { if (x) return x.id() };
266 $scope.suffix_list = [];
267 itemSvc.get_suffixes($scope.callNumber.owning_lib()).then(function(list){
268 $scope.suffix_list = list;
270 $scope.updateSuffix = function () {
271 angular.forEach($scope.copies, function(cp) {
272 cp.call_number().suffix($scope.suffix);
273 cp.call_number().ischanged(1);
277 $scope.prefix_list = [];
278 itemSvc.get_prefixes($scope.callNumber.owning_lib()).then(function(list){
279 $scope.prefix_list = list;
281 $scope.updatePrefix = function () {
282 angular.forEach($scope.copies, function(cp) {
283 cp.call_number().prefix($scope.prefix);
284 cp.call_number().ischanged(1);
288 $scope.classification_list = [];
289 itemSvc.get_classifications().then(function(list){
290 $scope.classification_list = list;
292 $scope.updateClassification = function () {
293 angular.forEach($scope.copies, function(cp) {
294 cp.call_number().label_class($scope.classification);
295 cp.call_number().ischanged(1);
299 $scope.updateLabel = function () {
300 angular.forEach($scope.copies, function(cp) {
301 cp.call_number().label($scope.label);
302 cp.call_number().ischanged(1);
306 $scope.$watch('callNumber.prefix()', function (v) {
307 if (typeof v != 'object') {
308 $scope.prefix = $scope.prefix_list.filter(function (p) {
311 $scope.callNumber.prefix($scope.prefix);
315 $scope.$watch('callNumber.suffix()', function (v) {
316 if (typeof v != 'object') {
317 $scope.suffix = $scope.suffix_list.filter( function (s) {
320 $scope.callNumber.suffix($scope.suffix);
324 $scope.$watch('callNumber.label_class()', function (v) {
325 if (typeof v != 'object') {
326 $scope.classification = $scope.classification_list.filter(function (c) {
329 $scope.callNumber.label_class($scope.classification);
333 $scope.$watch('callNumber.label()', function (v) {
337 $scope.prefix = $scope.callNumber.prefix();
338 $scope.suffix = $scope.callNumber.suffix();
339 $scope.classification = $scope.callNumber.label_class();
340 $scope.label = $scope.callNumber.label();
342 $scope.copy_count = $scope.copies.length;
343 $scope.orig_copy_count = $scope.copy_count;
345 $scope.changeCPCount = function () {
346 while ($scope.copy_count > $scope.copies.length) {
347 var cp = new egCore.idl.acp();
348 cp.id( --$scope.new_cp_id );
350 cp.circ_lib( $scope.lib );
351 cp.call_number( $scope.callNumber );
352 $scope.copies.push( cp );
353 $scope.allcopies.push( cp );
356 var how_many = $scope.copies.length - $scope.copy_count;
358 var dead = $scope.copies.splice($scope.copy_count,how_many);
359 $scope.callNumber.copies($scope.copies);
361 // Trimming the global list is a bit more tricky
362 angular.forEach( dead, function (d) {
363 angular.forEach( $scope.allcopies, function (l, i) {
364 if (l === d) $scope.allcopies.splice(i,1);
376 .directive("egVolEdit", function () {
382 '<div class="col-xs-1"><eg-org-selector selected="owning_lib" disableTest="cant_have_vols"></eg-org-selector></div>'+
383 '<div class="col-xs-1"><input type="number" min="{{orig_cn_count}}" ng-model="cn_count" ng-change="changeCNCount()"/></div>'+
384 '<div class="col-xs-10">'+
385 '<div class="container-fluid">'+
386 '<eg-vol-row ng-repeat="(cn,copies) in struct track by cn" copies="copies" allcopies="allcopies"></eg-vol-row>'+
391 scope: { allcopies: "=", struct: "=", lib: "@", record: "@" },
392 controller : ['$scope','itemSvc','egCore',
393 function ( $scope , itemSvc , egCore ) {
394 $scope.new_cn_id = 0;
395 $scope.first_cn = Object.keys($scope.struct)[0];
396 $scope.full_cn = $scope.struct[$scope.first_cn][0].call_number();
398 $scope.cn_count = Object.keys($scope.struct).length;
399 $scope.orig_cn_count = $scope.cn_count;
401 $scope.owning_lib = egCore.org.get($scope.lib);
402 $scope.$watch('owning_lib', function (l) {
403 angular.forEach( $scope.struct[$scope.first_cn], function (cp) {
404 cp.call_number().owning_lib( $scope.owning_lib.id() );
408 $scope.cant_have_vols = function (id) { return !egCore.org.CanHaveVolumes(id); };
410 $scope.$watch('cn_count', function (n) {
411 var o = Object.keys($scope.struct).length;
412 if (n > o) { // adding
413 for (var i = o; o < n; o++) {
414 var cn = new egCore.idl.acn();
415 cn.id( --$scope.new_cn_id );
417 cn.owning_lib( $scope.owning_lib.id() );
418 cn.record( $scope.full_cn.record() );
420 var cp = new egCore.idl.acp();
421 cp.id( --$scope.new_cp_id );
423 cp.circ_lib( $scope.owning_lib.id() );
424 cp.call_number( cn );
426 $scope.struct[cn.id()] = [cp];
427 $scope.allcopies.push(cp);
429 } else if (n < o) { // removing
430 var how_many = o - n;
433 .sort(function(a, b){return a-b})
435 for (var i = how_many; i > 0; i--) {
436 // Trimming the global list is a bit more tricky
437 angular.forEach($scope.struct[list[i]], function (d) {
438 angular.forEach( $scope.allcopies, function (l, j) {
439 if (l === d) $scope.allcopies.splice(j,1);
442 delete $scope.struct[list[i]];
455 .controller('EditCtrl',
456 ['$scope','$q','$routeParams','$location','$timeout','egCore','egNet','egGridDataProvider','itemSvc',
457 function($scope , $q , $routeParams , $location , $timeout , egCore , egNet , egGridDataProvider , itemSvc) {
459 $scope.show_vols = true;
460 $scope.show_copies = true;
462 $scope.tracker = function (x,f) { if (x) return x[f]() };
463 $scope.idTracker = function (x) { if (x) return $scope.tracker(x,'id') };
464 $scope.cant_have_vols = function (id) { return !egCore.org.CanHaveVolumes(id); };
466 $scope.orgById = function (id) { return egCore.org.get(id) }
467 $scope.statusById = function (id) {
468 return $scope.status_list.filter( function (s) { return s.id() == id } )[0];
470 $scope.locationById = function (id) {
471 return $scope.location_cache[''+id];
474 $scope.workingToComplete = function () {
475 angular.forEach( $scope.workingGridControls.selectedItems(), function (c) {
476 angular.forEach( itemSvc.copies, function (w, i) {
478 $scope.completed_copies = $scope.completed_copies.concat(itemSvc.copies.splice(i,1));
483 $scope.completeToWorking = function () {
484 angular.forEach( $scope.completedGridControls.selectedItems(), function (c) {
485 angular.forEach( $scope.completed_copies, function (w, i) {
487 itemSvc.copies = itemSvc.copies.concat($scope.completed_copies.splice(i,1));
492 createSimpleUpdateWatcher = function (field) {
493 $scope.$watch('working.' + field, function () {
494 var newval = $scope.working[field];
495 if (angular.isObject(newval)) { // we'll use the pkey
496 if (newval.id) newval = newval.id();
497 else if (newval.code) newval = newval.code();
500 if ($scope.workingGridControls && $scope.workingGridControls.selectedItems) {
502 $scope.workingGridControls.selectedItems(),
503 function (cp) { cp[field](newval); cp.ischanged(1); }
511 var dataKey = $routeParams.dataKey;
512 console.debug('dataKey: ' + dataKey);
514 if (dataKey && dataKey.length > 0) {
517 $scope.copytab = 'working';
519 $scope.summaryRecord = null;
520 $scope.record_id = null;
522 $scope.completed_copies = [];
523 $scope.location_orgs = [];
524 $scope.location_cache = {};
527 $scope.applyBatchCNValues = function () {
528 if ($scope.data.tree) {
529 angular.forEach($scope.data.tree, function(cn_hash) {
530 angular.forEach(cn_hash, function(copies) {
531 angular.forEach(copies, function(cp) {
532 if (typeof $scope.batch.classification != 'undefined' && $scope.batch.classification != '')
533 cp.call_number().label_class($scope.batch.classification);
534 if (typeof $scope.batch.prefix != 'undefined' && $scope.batch.prefix != '')
535 cp.call_number().prefix($scope.batch.prefix);
536 if (typeof $scope.batch.label != 'undefined' && $scope.batch.label != '')
537 cp.call_number().label($scope.batch.label);
538 if (typeof $scope.batch.suffix != 'undefined' && $scope.batch.suffix != '')
539 cp.call_number().suffix($scope.batch.suffix);
546 $scope.completedGridDataProvider = egGridDataProvider.instance({
547 get : function(offset, count) {
548 //return provider.arrayNotifier(itemSvc.copies, offset, count);
549 return this.arrayNotifier($scope.completed_copies, offset, count);
553 $scope.completedGridControls = {};
555 $scope.workingGridDataProvider = egGridDataProvider.instance({
556 get : function(offset, count) {
557 //return provider.arrayNotifier(itemSvc.copies, offset, count);
558 return this.arrayNotifier(itemSvc.copies, offset, count);
562 $scope.workingGridControls = {};
566 'open-ils.actor.anon_cache.get_value',
567 dataKey, 'edit-these-copies'
568 ).then(function (data) {
570 if (data.hide_vols) $scope.show_vols = false;
571 if (data.hide_copies) $scope.show_copies = false;
573 $scope.record_id = data.record_id;
575 if (data.copies && data.copies.length)
576 return itemSvc.fetchIds(data.copies);
578 if (data.raw && data.raw.length) {
580 /* data.raw must be an array of copies with (at least)
581 * the call number fleshed on each. For new copies
582 * create from whole cloth, the id for each should
583 * probably be negative and isnew() should return true.
584 * Each /distinct/ call number must have a distinct id
585 * as well, probably negative also if they're new. Clear?
590 function (cp) { itemSvc.addCopy(cp) }
593 return itemSvc.copies;
596 }).then( function() {
597 $scope.data = itemSvc;
598 $scope.workingGridDataProvider.refresh();
601 $scope.$watch('data.copies.length', function () {
602 if ($scope.data.copies) {
603 var base_orgs = $scope.data.copies.map(function(cp){
605 }).filter(function(e,i,a){
606 return a.lastIndexOf(e) === i;
610 angular.forEach(base_orgs, function(o) {
611 all_orgs = all_orgs.concat( egCore.org.fullPath(o, true) );
614 var final_orgs = all_orgs.filter(function(e,i,a){
615 return a.lastIndexOf(e) === i;
616 }).sort(function(a,b){return b-a});
618 if ($scope.location_orgs.toString() != final_orgs.toString()) {
619 $scope.location_orgs = final_orgs;
620 if ($scope.location_orgs.length) {
621 itemSvc.get_locations($scope.location_orgs).then(function(list){
622 angular.forEach(list, function(l) {
623 $scope.location_cache[ ''+l.id() ] = l;
625 $scope.location_list = list;
631 $scope.workingGridDataProvider.refresh();
634 $scope.suffix_list = [];
635 itemSvc.get_suffixes(egCore.auth.user().ws_ou()).then(function(list){
636 $scope.suffix_list = list;
639 $scope.prefix_list = [];
640 itemSvc.get_prefixes(egCore.auth.user().ws_ou()).then(function(list){
641 $scope.prefix_list = list;
644 $scope.classification_list = [];
645 itemSvc.get_classifications().then(function(list){
646 $scope.classification_list = list;
649 $scope.$watch('completed_copies.length', function () {
650 $scope.completedGridDataProvider.refresh();
653 $scope.location_list = [];
654 itemSvc.get_locations().then(function(list){
655 $scope.location_list = list;
657 createSimpleUpdateWatcher('location');
659 $scope.status_list = [];
660 itemSvc.get_statuses().then(function(list){
661 $scope.status_list = list;
663 createSimpleUpdateWatcher('status');
665 $scope.circ_mod_list = [];
666 itemSvc.get_circ_mods().then(function(list){
667 $scope.circ_mod_list = list;
669 createSimpleUpdateWatcher('circ_modifier');
671 $scope.circ_type_list = [];
672 itemSvc.get_circ_types().then(function(list){
673 $scope.circ_type_list = list;
675 createSimpleUpdateWatcher('circ_as_type');
677 $scope.age_protect_list = [];
678 itemSvc.get_age_protects().then(function(list){
679 $scope.age_protect_list = list;
681 createSimpleUpdateWatcher('age_protect');
683 createSimpleUpdateWatcher('circulate');
684 createSimpleUpdateWatcher('holdable');
685 createSimpleUpdateWatcher('fine_level');
686 createSimpleUpdateWatcher('loan_duration');
687 createSimpleUpdateWatcher('cost');
688 createSimpleUpdateWatcher('deposit');
689 createSimpleUpdateWatcher('deposit_amount');
690 createSimpleUpdateWatcher('mint_condition');
691 createSimpleUpdateWatcher('opac_visible');
692 createSimpleUpdateWatcher('ref');