From: Galen Charlton Date: Thu, 11 May 2017 15:29:25 +0000 (-0400) Subject: LP#1673857: add ability to set copy tags in volume/copy editor X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=2f4111d29af1f1372f7ddf5ea21644955dce897c;p=evergreen%2Fpines.git LP#1673857: add ability to set copy tags in volume/copy editor The copy editor now has a 'Copy Tags' button that can be used to assign or remove tags from a copy. A typeahead widget is used to allow the user to select an existing tag, but users can also use this interface to create an entirely new tag on the fly. Signed-off-by: Galen Charlton Signed-off-by: Josh Stompro Signed-off-by: Galen Charlton --- diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm index 4b81a46bb9..14a52d4b63 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm @@ -259,6 +259,51 @@ sub update_copy_notes { } +sub update_copy_tags { + my($class, $editor, $copy) = @_; + + return undef if $copy->isdeleted; + + my $evt; + my $incoming_maps = $copy->tags; + + for my $incoming_map (@$incoming_maps) { + next unless $incoming_map; + + if ($incoming_map->isnew) { + next if ($incoming_map->isdeleted); # if it was added and deleted in the same session + + my $tag_id; + if ($incoming_map->tag->isnew) { + my $new_tag = Fieldmapper::asset::copy_tag->new(); + $new_tag->owner( $incoming_map->tag->owner ); + $new_tag->label( $incoming_map->tag->label ); + $new_tag->tag_type( $incoming_map->tag->tag_type ); + $new_tag->pub( $incoming_map->tag->pub ); + my $tag = $editor->create_asset_copy_tag($new_tag) + or return $editor->event; + $tag_id = $tag->id; + } else { + $tag_id = $incoming_map->tag->id; + } + my $new_map = Fieldmapper::asset::copy_tag_copy_map->new(); + $new_map->copy( $copy->id ); + $new_map->tag( $tag_id ); + $incoming_map = $editor->create_asset_copy_tag_copy_map($new_map) + or return $editor->event; + + } elsif ($incoming_map->ischanged) { + $incoming_map = $editor->update_asset_copy_tag_copy_map($incoming_map) + } elsif ($incoming_map->isdeleted) { + $incoming_map = $editor->delete_asset_copy_tag_copy_map($incoming_map) + } + + } + + return undef; +} + + sub update_copy { my($class, $editor, $override, $vol, $copy, $retarget_holds, $force_delete_empty_bib) = @_; @@ -370,6 +415,8 @@ sub update_fleshed_copies { my $notes = $copy->notes; $copy->clear_notes; + my $tags = $copy->tags; + $copy->clear_tags; if( $copy->isdeleted ) { $evt = $class->delete_copy($editor, $override, $vol, $copy, $retarget_holds, $force_delete_empty_bib); @@ -394,6 +441,10 @@ sub update_fleshed_copies { $copy->notes( $notes ); $evt = $class->update_copy_notes($editor, $copy); + + $copy->tags( $tags ); + $evt = $class->update_copy_tags($editor, $copy); + return $evt if $evt; } diff --git a/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 b/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 index 12f1f77c11..fc2c5e6cee 100644 --- a/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 +++ b/Open-ILS/src/templates/staff/cat/volcopy/t_attr_edit.tt2 @@ -401,6 +401,15 @@ ng-options="a.id() as a.name() for a in floating_list" > +
+ +
diff --git a/Open-ILS/src/templates/staff/cat/volcopy/t_copy_tags.tt2 b/Open-ILS/src/templates/staff/cat/volcopy/t_copy_tags.tt2 new file mode 100644 index 0000000000..01932ad888 --- /dev/null +++ b/Open-ILS/src/templates/staff/cat/volcopy/t_copy_tags.tt2 @@ -0,0 +1,39 @@ +
+ + + +
diff --git a/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 b/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 index 44b328beb0..507205d843 100644 --- a/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 +++ b/Open-ILS/src/templates/staff/cat/volcopy/t_defaults.tt2 @@ -302,6 +302,12 @@ [% l('Floating') %] +
+ +
diff --git a/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js b/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js index 644be2f378..bbf44a20b4 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js +++ b/Open-ILS/web/js/ui/default/staff/cat/volcopy/app.js @@ -246,8 +246,9 @@ function(egCore , $q) { service.flesh = { flesh : 3, flesh_fields : { - acp : ['call_number','parts','stat_cat_entries', 'notes'], - acn : ['label_class','prefix','suffix'] + acp : ['call_number','parts','stat_cat_entries', 'notes', 'tags'], + acn : ['label_class','prefix','suffix'], + acptcm : ['tag'] } } @@ -786,6 +787,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore , auto_gen_barcode : false, statcats : true, copy_notes : true, + copy_tags : true, attributes : { status : true, loan_duration : true, @@ -1658,6 +1660,125 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore , }); } + $scope.copy_tags_dialog = function(copy_list) { + if (!angular.isArray(copy_list)) copy_list = [copy_list]; + + return $uibModal.open({ + templateUrl: './cat/volcopy/t_copy_tags', + animation: true, + controller: + ['$scope','$uibModalInstance', + function($scope , $uibModalInstance) { + + $scope.tag_map = []; + var tag_hash = {}; + var shared_tags = {}; + angular.forEach(copy_list, function (cp) { + angular.forEach(cp.tags(), function(tag) { + if (!(tag.tag().id() in shared_tags)) { + shared_tags[tag.tag().id()] = 1; + } else { + shared_tags[tag.tag().id()]++; + } + if (!(tag.tag().id() in tag_hash)) { + tag_hash[tag.tag().id()] = tag; + } + }); + }); + angular.forEach(tag_hash, function(value, key) { + if (shared_tags[key] == copy_list.length) { + $scope.tag_map.push(value); + } + }); + + $scope.tag_types = []; + egCore.pcrud.retrieveAll('cctt', {order_by : { cctt : 'label' }}, {atomic : true}).then(function(list) { + $scope.tag_types = list; + $scope.tag_type = $scope.tag_types[0].code(); // just pick a default + }); + + $scope.getTags = function(val) { + return egCore.pcrud.search('acpt', + { + owner : egCore.org.fullPath(egCore.auth.user().ws_ou(), true), + label : { 'startwith' : { + transform: 'evergreen.lowercase', + value : [ 'evergreen.lowercase', val ] + }}, + tag_type : $scope.tag_type + }, + { order_by : { 'acpt' : ['label'] } }, { atomic: true } + ).then(function(list) { + return list.map(function(item) { + return item.label(); + }); + }); + } + + $scope.addTag = function() { + var tagLabel = $scope.selectedLabel; + // clear the typeahead + $scope.selectedLabel = ""; + + // first, check tags already associated with the copy + var foundMatch = false; + angular.forEach($scope.tag_map, function(tag) { + if (tag.tag().label() == tagLabel && tag.tag().tag_type() == $scope.tag_type) { + foundMatch = true; + if (tag.isdeleted()) tag.isdeleted(0); // just deleting the mapping + } + }); + if (!foundMatch) { + egCore.pcrud.search('acpt', + { + owner : egCore.org.fullPath(egCore.auth.user().ws_ou(), true), + label : tagLabel, + tag_type : $scope.tag_type + }, + { order_by : { 'acpt' : ['label'] } }, { atomic: true } + ).then(function(list) { + if (list.length > 0) { + var newMap = new egCore.idl.acptcm(); + newMap.isnew(1); + newMap.copy(copy_list[0].id()); + newMap.tag(egCore.idl.Clone(list[0])); + $scope.tag_map.push(newMap); + } else { + var newTag = new egCore.idl.acpt(); + newTag.isnew(1); + newTag.owner(egCore.auth.user().ws_ou()); + newTag.label(tagLabel); + newTag.pub('t'); + newTag.tag_type($scope.tag_type); + + var newMap = new egCore.idl.acptcm(); + newMap.isnew(1); + newMap.copy(copy_list[0].id()); + newMap.tag(newTag); + $scope.tag_map.push(newMap); + } + }); + } + } + + $scope.ok = function(note) { + // in the multi-item case, this works OK for + // adding new maps to existing tags, but doesn't handle + // all possibilities + angular.forEach(copy_list, function (cp) { + cp.tags($scope.tag_map); + }); + $uibModalInstance.close(); + } + + $scope.cancel = function($event) { + $uibModalInstance.dismiss(); + $event.preventDefault(); + } + }] + }); + } + }]) .directive("egVolTemplate", function () { @@ -1676,6 +1797,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore , auto_gen_barcode : false, statcats : true, copy_notes : true, + copy_tags : true, attributes : { status : true, loan_duration : true,