[open-ils-commits] [GIT] Evergreen ILS branch rel_3_0 updated. a34a5909aeadc6d3c131c998c18843df2d96e639

Evergreen Git git at git.evergreen-ils.org
Thu Aug 9 09:24:29 EDT 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, rel_3_0 has been updated
       via  a34a5909aeadc6d3c131c998c18843df2d96e639 (commit)
       via  8a84d6c1167a0ad6b216754a067945fd8bc970fb (commit)
       via  9838c029670630ffd6d1d07199e4027b4e838aeb (commit)
       via  a0680431741497a0cd6c26b55da345648f26cd27 (commit)
       via  acce04a9d8826491611d0d3a6686a944e5fb781a (commit)
       via  e2c10c4895f44ded8312b025c7f25e1ad46ad2d6 (commit)
       via  1e25174f4edf7f990a15445893cc20a7d1fbc25f (commit)
       via  e7b47284745afbba8e07ef6deaf8c02be549b522 (commit)
      from  7af25eeef4e49549955aa8c1289a181bbf6d4351 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a34a5909aeadc6d3c131c998c18843df2d96e639
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Jul 6 15:33:05 2018 -0400

    LP#1773417: Use CN owning lib when adding copies
    
    This defaults the owner of new copies added to existing call numbers to the
    owning lib of the call number, rather than the workstation library.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>

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 2bd17d3..052b9c9 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
@@ -1307,7 +1307,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                     /* data.raw data structure looks like this:
                      * [{
                      *      callnumber : $cn_id, // optional, to add a copy to a cn
-                     *      owner      : $org, // optional, defaults to ws_ou
+                     *      owner      : $org, // optional, defaults to cn.owning_lib or ws_ou
                      *      label      : $cn_label, // optional, to supply a label on a new cn
                      *      barcode    : $cp_barcode // optional, to supply a barcode on a new cp
                      *      fast_add   : boolean // optional, to specify whether this came
@@ -1326,7 +1326,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                                 .then(function(cn) {
                                     var cp = new itemSvc.generateNewCopy(
                                         cn,
-                                        proto.owner || egCore.auth.user().ws_ou(),
+                                        proto.owner || cn.owning_lib(),
                                         $scope.is_fast_add,
                                         ((!$scope.only_vols) ? true : false)
                                     );
@@ -1381,7 +1381,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                                 // requirement
                                 var cp = new itemSvc.generateNewCopy(
                                     cn,
-                                    proto.owner || egCore.auth.user().ws_ou(),
+                                    proto.owner || cn.owning_lib(),
                                     $scope.is_fast_add,
                                     true
                                 );

commit 8a84d6c1167a0ad6b216754a067945fd8bc970fb
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Tue Jun 12 14:20:03 2018 -0400

    LP#1773417 Revamp item and call number tranfers
    
    This commit attempts to achieve the goals of both simplification and
    feature completeness/flexibility.  In brief, limit the number of
    marking and transfer options, then have the code decide the right
    action to take given the circumstances.
    
    There are now just two "marking" actions, one at the record level,
    one at the holdings level.  The holdings level mark will automatically
    mark the destination as specifically as possible from the selected row,
    which means either to the library or call number (vol) level.
    
    We are also now down to two transfer options: transfer the selected
    item, or transfer the selected call number.  Either option will use
    as much given context as possible, then fill in any blanks with
    reasonable defaults and actions.
    
    As part of the change, a number of functions and variables are also
    renamed.  This is all done for clarification, and in most cases is
    due to the variable or function now being used more generally (i.e.
    it is used in both the item and vol context, so it is confusing to
    be named 'volume_transfer_target', etc.).
    
    Finally, clear up a fair bit of now redundant and unused code.
    
    In rel_3_O:
    Conflicts:
    	Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>

diff --git a/Open-ILS/src/templates/staff/cat/catalog/index.tt2 b/Open-ILS/src/templates/staff/cat/catalog/index.tt2
index bb7d232..f2c75f7 100644
--- a/Open-ILS/src/templates/staff/cat/catalog/index.tt2
+++ b/Open-ILS/src/templates/staff/cat/catalog/index.tt2
@@ -48,10 +48,7 @@
       "[% l('Hold Transfer Destination set') %]";                
     s.MARK_CONJ_TARGET =                                                                                                            
       "[% l('Conjoined Item Target set') %]";                
-    s.MARK_VOL_TARGET =                                                                                                            
-      "[% l('Volume Transfer Target set') %]";                
-    s.MARK_ITEM_TARGET =                                                                                                            
-      "[% l('Item Transfer Target set') %]";                
+    s.MARK_HOLDINGS_TARGET = "[% l('Holdings transfer target set') %]";
     s.MARK_OVERLAY_TARGET =                                                                                                            
       "[% l('Record Overlay Target set') %]";                
 
diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2
index 5d49ad3..5c2630e 100644
--- a/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2
+++ b/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2
@@ -66,9 +66,9 @@
                 </a>
             </li>
             <li role="menuitem">
-                <a ng-click="markVolTransfer()" href="">
-                    [% l('Volume Transfer') %]
-                    <span class="target-record-aside" ng-if="current_voltransfer_target">[% l('(Currently [_1])', '{{current_voltransfer_target}}') %]</span>
+                <a ng-click="markHoldingsTransfer()" href="">
+                    [% l('Holdings Transfer') %]
+                    <span class="target-record-aside" ng-if="current_transfer_target">[% l('(Currently [_1])', '{{current_transfer_target}}') %]</span>
                 </a>
             </li>
             <li role="menuitem">
diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
index a6f269d..301ab05 100644
--- a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
+++ b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
@@ -49,11 +49,6 @@
       label="[% l('Request Items') %]"></eg-grid-action>
     <eg-grid-action handler="attach_to_peer_bib"
       label="[% l('Link as Conjoined to Previously Marked Bib Record') %]"></eg-grid-action>
-<!--
-    <eg-grid-action handler="markLibAsVolTarget"
-      label="[% l('Choose Library for Volume/Copy Transfer Destination') %]"></eg-grid-action>
--->
-
     <eg-grid-action handler="selectedHoldingsItemStatus" group="[% l('Show') %]"
       label="[% l('Item Status (list)') %]"></eg-grid-action>
     <eg-grid-action handler="selectedHoldingsItemStatusDetail" group="[% l('Show') %]"
@@ -69,10 +64,8 @@
       label="[% l('Item as Damaged') %]"></eg-grid-action>
     <eg-grid-action handler="selectedHoldingsMissing" group="[% l('Mark') %]"
       label="[% l('Item as Missing') %]"></eg-grid-action>
-    <eg-grid-action handler="markLibFromSelectedAsVolTarget" group="[% l('Mark') %]"
-      label="[% l('Library as Volume Transfer Destination') %]"></eg-grid-action>
-    <eg-grid-action handler="markVolAsItemTarget" group="[% l('Mark') %]" disabled="vols_not_shown"
-      label="[% l('Volume as Item Transfer Destination') %]"></eg-grid-action>
+    <eg-grid-action handler="markFromSelectedAsHoldingsTarget" group="[% l('Mark') %]"
+      label="[% l('Library/Volume as Transfer Destination') %]"></eg-grid-action>
 
     <eg-grid-action handler="selectedHoldingsVolAdd" group="[% l('Add') %]"
       label="[% l('Volumes') %]"></eg-grid-action>
@@ -97,23 +90,11 @@
     <eg-grid-action handler="selectedHoldingsVolCopyDelete" group="[% l('Delete') %]" disabled="copies_not_shown"
       label="[% l('Volumes and Copies') %]"></eg-grid-action>
 
-<!--
-    <eg-grid-action handler="transferVolumesToRecord" group="[% l('Transfer') %]"
-      label="[% l('Volumes to Previously Marked Record') %]"></eg-grid-action>
-    <eg-grid-action handler="transferVolumesToLibrary" group="[% l('Transfer') %]"
-      label="[% l('Volumes to Previously Marked Library') %]"></eg-grid-action>
--->
-
-    <eg-grid-action handler="transferVolumesToRecordAndLibrary" group="[% l('Transfer') %]"
+    <eg-grid-action handler="transferVolumes" group="[% l('Transfer') %]"
       label="[% l('Volumes to Previously Marked Destination') %]"></eg-grid-action>
 
-<!--
-    <eg-grid-action handler="changeItemOwningLib" group="[% l('Transfer') %]"
-      label="[% l('Copies to Previously Marked Library') %]"></eg-grid-action>
--->
-
     <eg-grid-action handler="transferItems" group="[% l('Transfer') %]"
-      label="[% l('Items to Previously Marked Volume') %]"></eg-grid-action>
+      label="[% l('Items to Previously Marked Destination') %]"></eg-grid-action>
 
     <eg-grid-field label="[% l('Owning Library') %]"  path="owner_label" flex="4" align="right" visible></eg-grid-field>
     <eg-grid-field label="[% l('Call Number') %]"     path="call_number.label" visible></eg-grid-field>
diff --git a/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js b/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js
index 9d6a8d7..90fbcf0 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js
@@ -720,7 +720,7 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
     }
 
     $scope.transferCopies = function(copies) {
-        var xfer_target = egCore.hatch.getLocalItem('eg.cat.item_transfer_target');
+        var xfer_target = egCore.hatch.getLocalItem('eg.cat.transfer_target_vol');
         var copy_ids = copies.map(
             function(curr,idx,arr) {
                 return curr.id;
diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
index a91b04d..c6fbe42 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
@@ -376,7 +376,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     }
 
     $scope.current_overlay_target     = egCore.hatch.getLocalItem('eg.cat.marked_overlay_record');
-    $scope.current_voltransfer_target = egCore.hatch.getLocalItem('eg.cat.marked_volume_transfer_record');
+    $scope.current_transfer_target    = egCore.hatch.getLocalItem('eg.cat.transfer_target_record');
     $scope.current_conjoined_target   = egCore.hatch.getLocalItem('eg.cat.marked_conjoined_record');
 
     $scope.quickReceive = function () {
@@ -441,11 +441,12 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         ngToast.create(egCore.strings.MARK_CONJ_TARGET);
     };
 
-    $scope.markVolTransfer = function () {
-        ngToast.create(egCore.strings.MARK_VOL_TARGET);
-        $scope.current_voltransfer_target = $scope.record_id;
-        egCore.hatch.setLocalItem('eg.cat.marked_volume_transfer_record',$scope.record_id);
-        egCore.hatch.removeLocalItem('eg.cat.volume_transfer_target');
+    $scope.markHoldingsTransfer = function () {
+        $scope.current_transfer_target = $scope.record_id;
+        egCore.hatch.setLocalItem('eg.cat.transfer_target_record',$scope.record_id);
+        egCore.hatch.removeLocalItem('eg.cat.transfer_target_lib');
+        egCore.hatch.removeLocalItem('eg.cat.transfer_target_vol');
+        ngToast.create(egCore.strings.MARK_HOLDINGS_TARGET);
     };
 
     $scope.markOverlay = function () {
@@ -456,10 +457,10 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
 
     $scope.clearRecordMarks = function () {
         $scope.current_overlay_target     = null;
-        $scope.current_voltransfer_target = null;
+        $scope.current_transfer_target    = null;
         $scope.current_conjoined_target   = null;
         $scope.current_hold_transfer_dest = null;
-        egCore.hatch.removeLocalItem('eg.cat.marked_volume_transfer_record');
+        egCore.hatch.removeLocalItem('eg.cat.transfer_target_record');
         egCore.hatch.removeLocalItem('eg.cat.marked_conjoined_record');
         egCore.hatch.removeLocalItem('eg.cat.marked_overlay_record');
         egCore.hatch.removeLocalItem('eg.circ.hold.title_transfer_target');
@@ -1306,56 +1307,26 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         $timeout(function() { $window.open(url, '_blank') });
     }
 
-    $scope.markVolAsItemTarget = function() {
-        if ($scope.holdingsGridControls.selectedItems()[0].call_number.id) { // cn.id missing when vols are collapsed
-            egCore.hatch.setLocalItem(
-                'eg.cat.item_transfer_target',
-                $scope.holdingsGridControls.selectedItems()[0].call_number.id
-            );
-            ngToast.create(egCore.strings.MARK_ITEM_TARGET);
-        }
-    }
-
-    $scope.markLibAsVolTarget = function() {
-        var recId = $scope.record_id;
-        return $uibModal.open({
-            templateUrl: './cat/catalog/t_choose_vol_target_lib',
-            animation: true,
-            controller:
-                   ['$scope','$uibModalInstance',
-            function($scope , $uibModalInstance) {
-
-                var orgId = egCore.hatch.getLocalItem('eg.cat.volume_transfer_target') || 1;
-                $scope.org = egCore.org.get(orgId);
-                $scope.cant_have_vols = function (id) { return !egCore.org.CanHaveVolumes(id); };
-                $scope.ok = function(org) {
-                    egCore.hatch.setLocalItem(
-                        'eg.cat.volume_transfer_target',
-                        org.id()
-                    );
-                    egCore.hatch.setLocalItem(
-                        'eg.cat.marked_volume_transfer_record',
-                        recId
-                    );
-                    $uibModalInstance.close();
-                }
-                $scope.cancel = function($event) {
-                    $uibModalInstance.dismiss();
-                    $event.preventDefault();
-                }
-            }]
-        });
-    }
-    $scope.markLibFromSelectedAsVolTarget = function() {
+    $scope.markFromSelectedAsHoldingsTarget = function() {
         egCore.hatch.setLocalItem(
-            'eg.cat.volume_transfer_target',
+            'eg.cat.transfer_target_lib',
             $scope.holdingsGridControls.selectedItems()[0].owner_id
         );
         egCore.hatch.setLocalItem(
-            'eg.cat.marked_volume_transfer_record',
+            'eg.cat.transfer_target_record',
             $scope.record_id
         );
-        ngToast.create(egCore.strings.MARK_VOL_TARGET);
+        if ($scope.holdingsGridControls.selectedItems()[0].call_number.id) { // cn.id missing when vols are collapsed, or we are on an empty lib
+            egCore.hatch.setLocalItem(
+                'eg.cat.transfer_target_vol',
+                $scope.holdingsGridControls.selectedItems()[0].call_number.id
+            );
+        } else {
+            // clear out the stale value if we're on a lib-only
+            // or vol-collapsed row
+            egCore.hatch.removeLocalItem('eg.cat.transfer_target_vol');
+        }
+        ngToast.create(egCore.strings.MARK_HOLDINGS_TARGET);
     }
 
     $scope.selectedHoldingsItemStatusDetail = function (){
@@ -1369,20 +1340,35 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         );
     }
 
-    $scope.transferVolumesToRecord = function (){
-        var target_record = egCore.hatch.getLocalItem('eg.cat.marked_volume_transfer_record');
-        if (!target_record) return;
-        if ($scope.record_id == target_record) return;
-        var items = $scope.holdingsGridControls.selectedItems();
-        if (!items.length) return;
+    $scope.transferVolumes = function (){
+        var target_record = egCore.hatch.getLocalItem('eg.cat.transfer_target_record');
+        var target_lib = egCore.hatch.getLocalItem('eg.cat.transfer_target_lib');
+        if (!target_lib
+            && (!target_record || ($scope.record_id == target_record) )
+        ) return;
 
-        var vols_to_move   = {};
-        angular.forEach(items, function(item) {
-            if (!(item.call_number.owning_lib in vols_to_move)) {
-                vols_to_move[item.call_number.owning_lib] = new Array;
+        var vols_to_move = {};
+        if (target_lib) {
+            // we're moving volumes to a different library
+            var vol_ids = gatherSelectedVolumeIds();
+            if (vol_ids.length) {
+                vols_to_move[target_lib] = vol_ids;
+
+                // if we're *only* switching libs,
+                // grab the current record as the target
+                target_record = target_record || $scope.record_id;
             }
-            vols_to_move[item.call_number.owning_lib].push(item.call_number.id);
-        });
+        } else {
+            // we're moving volumes to the same library they exist in
+            // currently, but on a different record
+            var items = $scope.holdingsGridControls.selectedItems();
+            angular.forEach(items, function(item) {
+                if (!(item.call_number.owning_lib in vols_to_move)) {
+                    vols_to_move[item.call_number.owning_lib] = new Array;
+                }
+                vols_to_move[item.call_number.owning_lib].push(item.call_number.id);
+            });
+        }
 
         var promises = [];        
         angular.forEach(vols_to_move, function(vols, owning_lib) {
@@ -1408,54 +1394,35 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         });
     }
 
-    function transferVolumes(new_record){
-        var xfer_target = egCore.hatch.getLocalItem('eg.cat.volume_transfer_target');
-
-        if (xfer_target) {
-            egCore.net.request(
-                'open-ils.cat',
-                'open-ils.cat.asset.volume.batch.transfer.override',
-                egCore.auth.token(), {
-                    docid   : (new_record ? new_record : $scope.record_id),
-                    lib     : xfer_target,
-                    volumes : gatherSelectedVolumeIds()
-                }
-            ).then(function(success) {
-                if (success) {
-                    ngToast.create(egCore.strings.VOLS_TRANSFERED);
-                    holdingsSvcInst.fetchAgain().then(function() {
-                        $scope.holdingsGridDataProvider.refresh();
-                    });
-                } else {
-                    alert('Could not transfer volumes!');
-                }
-            });
-        }
-        
-    }
-
-    $scope.transferVolumesToLibrary = function() {
-        transferVolumes();
-    }
-
-    $scope.transferVolumesToRecordAndLibrary = function() {
-        var target_record = egCore.hatch.getLocalItem('eg.cat.marked_volume_transfer_record');
-        if (!target_record) return;
-        transferVolumes(target_record);
-    }
-
     // this "transfers" selected copies to a new owning library,
-    // auto-creating volumes and deleting unused volumes as required.
-    $scope.changeItemOwningLib = function() {
-        var xfer_target = egCore.hatch.getLocalItem('eg.cat.volume_transfer_target');
+    // auto-creating volumes as required
+    $scope.transferItemsAutoFill = function() {
+        var target_record = egCore.hatch.getLocalItem('eg.cat.transfer_target_record');
+        var target_lib = egCore.hatch.getLocalItem('eg.cat.transfer_target_lib');
+        if (!target_lib
+            && (!target_record || ($scope.record_id == target_record) )
+        ) return;
+
         var items = $scope.holdingsGridControls.selectedItems();
-        if (!xfer_target || !items.length) {
+        if (!items.length) {
             return;
         }
+
         var vols_to_move   = {};
         var copies_to_move = {};
         angular.forEach(items, function(item) {
-            if (item.call_number.owning_lib != xfer_target) {
+            var needs_move = false;
+            if (target_lib
+                && (item.call_number.owning_lib != target_lib)) {
+                    item.call_number.owning_lib = target_lib;
+                    needs_move = true;
+            }
+            if (target_record
+                && (item.call_number.record != target_record)) {
+                    item.call_number.record = target_record;
+                    needs_move = true;
+            }
+            if (needs_move) {
                 if (item.call_number.id in vols_to_move) {
                     copies_to_move[item.call_number.id].push(item.id);
                 } else {
@@ -1465,7 +1432,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                 }
             }
         });
-    
+
         var promises = [];
         angular.forEach(vols_to_move, function(vol) {
             promises.push(egCore.net.request(
@@ -1473,8 +1440,8 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                 'open-ils.cat.call_number.find_or_create',
                 egCore.auth.token(),
                 vol.label,
-                vol.record,
-                xfer_target,
+                vol.record, // may be new
+                vol.owning_lib, // may be new
                 vol.prefix.id,
                 vol.suffix.id,
                 vol.label_class
@@ -1499,9 +1466,16 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     }
 
     $scope.transferItems = function (){
-        var xfer_target = egCore.hatch.getLocalItem('eg.cat.item_transfer_target');
+        var xfer_target = egCore.hatch.getLocalItem('eg.cat.transfer_target_vol');
+
+        if (!xfer_target) {
+            // we have no specific volume, let's try to fill in the
+            // blanks instead
+            return $scope.transferItemsAutoFill();
+        }
+
         var copy_ids = gatherSelectedHoldingsIds();
-        if (xfer_target && copy_ids.length > 0) {
+        if (copy_ids.length > 0) {
             egCore.net.request(
                 'open-ils.cat',
                 'open-ils.cat.transfer_copies_to_volume',
diff --git a/Open-ILS/web/js/ui/default/staff/circ/services/item.js b/Open-ILS/web/js/ui/default/staff/circ/services/item.js
index 4d722b7..057d332 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/services/item.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/services/item.js
@@ -769,7 +769,7 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
     // this "transfers" selected copies to a new owning library,
     // auto-creating volumes and deleting unused volumes as required.
     service.changeItemOwningLib = function(items) {
-        var xfer_target = egCore.hatch.getLocalItem('eg.cat.volume_transfer_target');
+        var xfer_target = egCore.hatch.getLocalItem('eg.cat.transfer_target_lib');
         if (!xfer_target || !items.length) {
             return;
         }
@@ -794,7 +794,7 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
         });
 
         var promises = [];
-        angular.forEach(vols_to_move, function(vol) {
+        angular.forEach(vols_to_move, function(vol, vol_id) {
             promises.push(egCore.net.request(
                 'open-ils.cat',
                 'open-ils.cat.call_number.find_or_create',
@@ -813,24 +813,21 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
                     'open-ils.cat.transfer_copies_to_volume',
                     egCore.auth.token(),
                     resp.acn_id,
-                    copies_to_move[vol.id]
+                    copies_to_move[vol_id]
                 );
             }));
         });
 
-        angular.forEach(
-            items,
-            function(cp){
-                promises.push(
-                    function(){ service.add_barcode_to_list(cp.barcode) }
-                )
+        $q.all(promises)
+        .then(
+            function() {
+                angular.forEach(items, function(cp){service.add_barcode_to_list(cp.barcode)});
             }
         );
-        $q.all(promises);
     }
 
     service.transferItems = function (items){
-        var xfer_target = egCore.hatch.getLocalItem('eg.cat.item_transfer_target');
+        var xfer_target = egCore.hatch.getLocalItem('eg.cat.transfer_target_vol');
         var copy_ids = service.gatherSelectedHoldingsIds(items);
         if (xfer_target && copy_ids.length > 0) {
             egCore.net.request(

commit 9838c029670630ffd6d1d07199e4027b4e838aeb
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Wed May 30 12:43:08 2018 -0400

    LP#1773417 Improve empty volume handling
    
    The crux of this patch is to rethink how we handle the volume-only
    editing interface.  Previously, we were attempting to distinguish
    between when the volume was the only thing *showing* and when it
    was actually the only thing *existing*.
    
    We have now removed that distinction, so the volume-only interface
    only cares about the volume regardless of the possible presence of
    a copy.  This simplifies the interface logic, and reduces or
    eliminates the chance of the hidden copy editor interfering with
    the volume adding/editing functions.
    
    Other smaller changes here include:
    - Teach the edit function to pick up copy-less "empty" call numbers
    - Reduce and clarify the arguments to spawnHoldingsAdd
      We had three arguments, but two were simply inversions of one another
      in every case.  Reduce to two arguments and give them more meaningful
      labels
    - Fix typo ("emtpy") preventing proper button disabling for blank call
      numbers
    - Move call number emptiness check from updateLabel() function to value
      watch instead.  This ensure that any updates to that value (even those
      not using the update function) will flip the flag appropriately.  This
      fixes a timing bug which prevented call numbers from being saved
      without further edits in some cases.
    
    Ultimately, as J. Boyer suggests, we would be better off not generating
    the copy editor at all (rather than just hiding it), but we're a few
    steps off from that yet.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>

diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
index 14be87b..a91b04d 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
@@ -1135,7 +1135,10 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         angular.forEach(
             $scope.holdingsGridControls.selectedItems(),
             function (item) {
-                if (item.copy_count == 0)
+                if (item.copy_count == 0 || (!item.id && item.call_number))
+                    // we are in a compressed row with no copies, or we are in a single
+                    // call number row with no copy (testing for presence of 'id')
+                    // In either case, the call number is 'empty'
                     cn_id_list.push(item.call_number.id)
             }
         );
@@ -1225,13 +1228,13 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     $scope.selectedHoldingsVolCopyDelete = function () { $scope.selectedHoldingsDelete(true,true) }
     $scope.selectedHoldingsEmptyVolCopyDelete = function () { $scope.selectedHoldingsDelete(true,false) }
 
-    spawnHoldingsAdd = function (vols,copies,only_add_vol){
+    spawnHoldingsAdd = function (add_vols,add_copies){
         var raw = [];
-        if (copies) { // just a copy on existing volumes
+        if (!add_vols && add_copies) { // just a copy on existing volumes
             angular.forEach(gatherSelectedVolumeIds(), function (v) {
                 raw.push( {callnumber : v} );
             });
-        } else if (vols) {
+        } else if (add_vols) {
             if (typeof $scope.holdingsGridControls.selectedItems == "function" &&
                 $scope.holdingsGridControls.selectedItems().length > 0) {
                 angular.forEach($scope.holdingsGridControls.selectedItems(),
@@ -1257,8 +1260,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                 record_id: $scope.record_id,
                 raw: raw,
                 hide_vols : false,
-                hide_copies : ((only_add_vol) ? true : false),
-                only_add_vol : only_add_vol
+                hide_copies : !add_copies
             }
         ).then(function(key) {
             if (key) {
@@ -1269,9 +1271,9 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
             }
         });
     }
-    $scope.selectedHoldingsVolCopyAdd = function () { spawnHoldingsAdd(true,false,false) }
-    $scope.selectedHoldingsCopyAdd = function () { spawnHoldingsAdd(false,true,false) }
-    $scope.selectedHoldingsVolAdd = function () { spawnHoldingsAdd(true,false,true) }
+    $scope.selectedHoldingsVolCopyAdd = function () { spawnHoldingsAdd(true,true) }
+    $scope.selectedHoldingsCopyAdd = function () { spawnHoldingsAdd(false,true) }
+    $scope.selectedHoldingsVolAdd = function () { spawnHoldingsAdd(true,false) }
 
     spawnHoldingsEdit = function (hide_vols,hide_copies){
         egCore.net.request(
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 2e62733..2bd17d3 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
@@ -573,7 +573,7 @@ function(egCore , $q) {
         controller : ['$scope','itemSvc','egCore',
             function ( $scope , itemSvc , egCore ) {
                 $scope.callNumber =  $scope.copies[0].call_number();
-                if (!$scope.callNumber.label()) $scope.callNumber.emtpy_label = true;
+                if (!$scope.callNumber.label()) $scope.callNumber.empty_label = true;
 
                 $scope.empty_label = false;
                 $scope.empty_label_string = window.empty_label_string;
@@ -703,11 +703,6 @@ function(egCore , $q) {
                 }
 
                 $scope.updateLabel = function () {
-                    if ($scope.label == '') {
-                        $scope.callNumber.empty_label = $scope.empty_label = true;
-                    } else {
-                        $scope.callNumber.empty_label = $scope.empty_label = false;
-                    }
                     angular.forEach($scope.copies, function(cp) {
                         cp.call_number().label($scope.label);
                         cp.call_number().ischanged(1);
@@ -716,6 +711,11 @@ function(egCore , $q) {
 
                 $scope.$watch('callNumber.label()', function (v) {
                     $scope.label = v;
+                    if ($scope.label == '') {
+                        $scope.callNumber.empty_label = $scope.empty_label = true;
+                    } else {
+                        $scope.callNumber.empty_label = $scope.empty_label = false;
+                    }
                 });
 
                 $scope.prefix = $scope.callNumber.prefix();
@@ -1297,9 +1297,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                     $scope.show_copies = false;
                     $scope.only_vols = true;
                 }
-                if (data.only_add_vol) {
-                    $scope.only_add_vol = true;
-                }
 
                 $scope.record_id = data.record_id;
 
@@ -1402,7 +1399,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                     return itemSvc.copies;
                 }
 
-                if (!$scope.only_add_vol && data.copies && data.copies.length)
+                if (data.copies && data.copies.length)
                     return itemSvc.fetchIds(data.copies).then(fetchRaw);
 
                 return fetchRaw();
@@ -1421,7 +1418,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
             angular.forEach(
                 itemSvc.copies,
                 function (i) {
-                    if (!$scope.only_add_vol) {
+                    if (!$scope.only_vols) {
                         if (i.duplicate_barcode || i.empty_barcode || i.call_number().empty_label) {
                             can_save = false;
                         }
@@ -1431,7 +1428,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                 }
             );
 
-            if ($scope.forms.myForm && $scope.forms.myForm.$invalid) {
+            if (!$scope.only_vols && $scope.forms.myForm && $scope.forms.myForm.$invalid) {
                 can_save = false;
             }
 
@@ -1724,7 +1721,7 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                     cnHash[cn_id].suffix(cnHash[cn_id].suffix().id()); // un-object-ize some fields
             });
 
-            if ($scope.only_add_vol) { // strip off copies when we're in add-empty-vol mode
+            if ($scope.only_vols) { // strip off copies when we're in vol-only mode
                 angular.forEach(cnHash, function (v, k) {
                     cnHash[k].copies([]);
                 });

commit a0680431741497a0cd6c26b55da345648f26cd27
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Fri May 25 22:20:49 2018 -0400

    LP#1773417 Relabel "Add Volumes" button
    
    Now that we have an interface for adding empty volumes, we need to be
    more explicit that this button is for adding complete copies, not just
    volumes.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>

diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2
index c1e326e..5d49ad3 100644
--- a/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2
+++ b/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2
@@ -24,7 +24,7 @@
   <div class="col-md-6">
     <div class="pull-right">
     <button type="button" class="btn btn-default" ng-click="selectedHoldingsVolCopyAdd()">
-        [% l('Add Volumes') %]
+        [% l('Add Copies') %]
     </button>
     <div class="btn-group" uib-dropdown dropdown-append-to-body>
         <button id="serials-button" type="button" class="btn btn-default" uib-dropdown-toggle>

commit acce04a9d8826491611d0d3a6686a944e5fb781a
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Wed May 23 14:39:49 2018 -0400

    LP#1715697 Refactor empty volume adding
    
    The new ability to add empty volumes was causing the existing
    ability to add new volume/copy combos to not work as expected.
    More specifically, added volume/copy combos would not generate
    in the selected org_unit, but always in the ws_ou.
    
    To correct this, this change refactors/reverts significant portions of
    920f585052ef809ea6ca1e447d416ada871b467c.  Reasons include:
    
    - Existing code distinguishs 'adds' from 'edits' via two wrappers,
    spawnHoldingsAdd and spawnHoldingsEdit.  With this commit, empty volume
    adding now extends the 'add' function rather than the 'edit' one, as
    this seems more intuitive.
    
    - The previous change had extended both the catalog app and another
    similar directive which is only used in a merging context.  Since the
    merge context had no ability to add anything, and the new code was not
    wired up to the interface, this has simply been removed (for now).
    
    - The volcopy app is set up around the concept of passed in
    'prototype' vol/copy objects of varying degrees of completeness.  It
    then loops over these to generate the interface.  The previous code
    extended this setup with a loop over a potential 'owners' array to
    generate empty volumes, but this unrelated loop within a loop seemed
    counterintuitive (and was the source of the original bug).  This change
    has been removed, and empty volume creation now hews more closely to
    the original model.
    
    While this commit appears large, when viewed in the context of the
    pre-920f58505 code, it is quite limited in scope.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>

diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
index 4e207ea..14be87b 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
@@ -1112,15 +1112,6 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         $scope.holdings_cb_changed(item.checkbox,item.checked);
     }
 
-    function gatherSelectedOwners () {
-        var owner_list = [];
-        angular.forEach(
-            $scope.holdingsGridControls.selectedItems(),
-            function (item) { owner_list.push(item.owner_id) }
-        );
-        return owner_list;
-    }
-
     function gatherSelectedHoldingsIds () {
         var cp_id_list = [];
         angular.forEach(
@@ -1234,7 +1225,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     $scope.selectedHoldingsVolCopyDelete = function () { $scope.selectedHoldingsDelete(true,true) }
     $scope.selectedHoldingsEmptyVolCopyDelete = function () { $scope.selectedHoldingsDelete(true,false) }
 
-    spawnHoldingsAdd = function (vols,copies){
+    spawnHoldingsAdd = function (vols,copies,only_add_vol){
         var raw = [];
         if (copies) { // just a copy on existing volumes
             angular.forEach(gatherSelectedVolumeIds(), function (v) {
@@ -1247,7 +1238,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                     function (item) {
                         raw.push({
                             owner : item.owner_id,
-                            label : item.call_number.label
+                            label : ((item.call_number) ? item.call_number.label : null)
                         });
                     });
             } else {
@@ -1266,7 +1257,8 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                 record_id: $scope.record_id,
                 raw: raw,
                 hide_vols : false,
-                hide_copies : false
+                hide_copies : ((only_add_vol) ? true : false),
+                only_add_vol : only_add_vol
             }
         ).then(function(key) {
             if (key) {
@@ -1277,31 +1269,22 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
             }
         });
     }
-    $scope.selectedHoldingsVolCopyAdd = function () { spawnHoldingsAdd(true,false) }
-    $scope.selectedHoldingsCopyAdd = function () { spawnHoldingsAdd(false,true) }
-
-    spawnHoldingsEdit = function (hide_vols,hide_copies,add_vol){
-
-        var raw;
-        if (add_vol) {
-            raw = [{callnumber:null}];
-        } else {
-            raw = gatherSelectedEmptyVolumeIds().map(
-                function(v){ return { callnumber : v } }
-            );
-        }
+    $scope.selectedHoldingsVolCopyAdd = function () { spawnHoldingsAdd(true,false,false) }
+    $scope.selectedHoldingsCopyAdd = function () { spawnHoldingsAdd(false,true,false) }
+    $scope.selectedHoldingsVolAdd = function () { spawnHoldingsAdd(true,false,true) }
 
+    spawnHoldingsEdit = function (hide_vols,hide_copies){
         egCore.net.request(
             'open-ils.actor',
             'open-ils.actor.anon_cache.set_value',
             null, 'edit-these-copies', {
                 record_id: $scope.record_id,
                 copies: gatherSelectedHoldingsIds(),
-                raw: raw,
+                raw: gatherSelectedEmptyVolumeIds().map(
+                    function(v){ return { callnumber : v } }
+                ),
                 hide_vols : hide_vols,
-                hide_copies : hide_copies,
-                only_add_vol : ((add_vol) ? true : false),
-                owners : gatherSelectedOwners()
+                hide_copies : hide_copies
             }
         ).then(function(key) {
             if (key) {
@@ -1316,8 +1299,6 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     $scope.selectedHoldingsVolEdit = function () { spawnHoldingsEdit(false,true) }
     $scope.selectedHoldingsCopyEdit = function () { spawnHoldingsEdit(true,false) }
 
-    $scope.selectedHoldingsVolAdd = function () { spawnHoldingsEdit(false,true,true) }
-
     $scope.selectedHoldingsItemStatus = function (){
         var url = egCore.env.basePath + 'cat/item/search/' + gatherSelectedHoldingsIds().join(',')
         $timeout(function() { $window.open(url, '_blank') });
diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js b/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
index 0decd88..2fa67b4 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
@@ -354,15 +354,6 @@ function(egCore , $q) {
                     }
                 });
 
-                function gatherSelectedOwners () {
-                    var owner_list = [];
-                    angular.forEach(
-                        $scope.holdingsGridControls.selectedItems(),
-                        function (item) { owner_list.push(item.owner_id) }
-                    );
-                    return owner_list;
-                }
-
                 function gatherHoldingsIds () {
                     var cp_id_list = [];
                     angular.forEach(
@@ -372,7 +363,7 @@ function(egCore , $q) {
                     return cp_id_list;
                 }
 
-                var spawn_volume_editor = function (copies_too,add_vol) {
+                var spawn_volume_editor = function (copies_too) {
                     egCore.net.request(
                         'open-ils.actor',
                         'open-ils.actor.anon_cache.set_value',
@@ -380,9 +371,7 @@ function(egCore , $q) {
                             record_id: $scope.recordId,
                             copies: gatherHoldingsIds(),
                             hide_vols : false,
-                            hide_copies : ((copies_too) ? false : true),
-                            only_add_vol : ((add_vol) ? true : false),
-                            owners : gatherSelectedOwners()
+                            hide_copies : ((copies_too) ? false : true)
                         }
                     ).then(function(key) {
                         if (key) {
@@ -403,14 +392,11 @@ function(egCore , $q) {
                         }
                     });
                 }
-                $scope.add_emtpy_volumes = function() {
-                    spawn_volume_editor(false,true);
-                }
                 $scope.edit_volumes = function() {
-                    spawn_volume_editor(false,false);
+                    spawn_volume_editor(false);
                 }
                 $scope.edit_copies = function() {
-                    spawn_volume_editor(true,false);
+                    spawn_volume_editor(true);
                 }
 
                 function load_holdings() {
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 e98bde7..2e62733 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
@@ -1292,8 +1292,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
         ).then(function (data) {
 
             if (data) {
-                var owners = [ egCore.auth.user().ws_ou() ];
-
                 if (data.hide_vols && !$scope.defaults.always_volumes) $scope.show_vols = false;
                 if (data.hide_copies) {
                     $scope.show_copies = false;
@@ -1301,9 +1299,6 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                 }
                 if (data.only_add_vol) {
                     $scope.only_add_vol = true;
-                    $scope.only_vols = true;
-                    $scope.show_copies = false;
-                    owners = data.owners;
                 }
 
                 $scope.record_id = data.record_id;
@@ -1347,56 +1342,59 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                                     itemSvc.addCopy(cp)
                                 });
                             } else {
-                                angular.forEach(owners, function(owner) {
-                                    var cn = new egCore.idl.acn();
-                                    cn.id( --itemSvc.new_cn_id );
-                                    cn.isnew( true );
-                                    cn.prefix( $scope.defaults.prefix || -1 );
-                                    cn.suffix( $scope.defaults.suffix || -1 );
-                                    cn.owning_lib( owner );
-                                    cn.record( $scope.record_id );
-                                    egCore.org.settings(
-                                        ['cat.default_classification_scheme'],
-                                        cn.owning_lib()
-                                    ).then(function (val) {
-                                        cn.label_class(
-                                            $scope.defaults.classification ||
-                                            val['cat.default_classification_scheme'] ||
-                                            1
-                                        );
-                                        if (proto.label) {
-                                            cn.label( proto.label );
-                                        } else {
-                                            egCore.net.request(
-                                                'open-ils.cat',
-                                                'open-ils.cat.biblio.record.marc_cn.retrieve',
-                                                $scope.record_id,
-                                                cn.label_class()
-                                            ).then(function(cn_array) {
-                                                if (cn_array.length > 0) {
-                                                    for (var field in cn_array[0]) {
-                                                        cn.label( cn_array[0][field] );
-                                                        break;
-                                                    }
+                                var cn = new egCore.idl.acn();
+                                cn.id( --itemSvc.new_cn_id );
+                                cn.isnew( true );
+                                cn.prefix( $scope.defaults.prefix || -1 );
+                                cn.suffix( $scope.defaults.suffix || -1 );
+                                cn.owning_lib( proto.owner || egCore.auth.user().ws_ou() );
+                                cn.record( $scope.record_id );
+                                egCore.org.settings(
+                                    ['cat.default_classification_scheme'],
+                                    cn.owning_lib()
+                                ).then(function (val) {
+                                    cn.label_class(
+                                        $scope.defaults.classification ||
+                                        val['cat.default_classification_scheme'] ||
+                                        1
+                                    );
+                                    if (proto.label) {
+                                        cn.label( proto.label );
+                                    } else {
+                                        egCore.net.request(
+                                            'open-ils.cat',
+                                            'open-ils.cat.biblio.record.marc_cn.retrieve',
+                                            $scope.record_id,
+                                            cn.label_class()
+                                        ).then(function(cn_array) {
+                                            if (cn_array.length > 0) {
+                                                for (var field in cn_array[0]) {
+                                                    cn.label( cn_array[0][field] );
+                                                    break;
                                                 }
-                                            });
-                                        }
-                                    });
+                                            }
+                                        });
+                                    }
+                                });
 
-                                    var cp = new itemSvc.generateNewCopy(
-                                        cn,
-                                        proto.owner || egCore.auth.user().ws_ou(),
-                                        $scope.is_fast_add,
-                                        true
-                                    );
+                                // If we are adding an empty vol,
+                                // this is ultimately just a placeholder copy
+                                // which gets removed before saving.
+                                // TODO: consider ways to remove this
+                                // requirement
+                                var cp = new itemSvc.generateNewCopy(
+                                    cn,
+                                    proto.owner || egCore.auth.user().ws_ou(),
+                                    $scope.is_fast_add,
+                                    true
+                                );
 
-                                    if (proto.barcode) {
-                                        cp.barcode( proto.barcode );
-                                        cp.empty_barcode = false;
-                                    }
+                                if (proto.barcode) {
+                                    cp.barcode( proto.barcode );
+                                    cp.empty_barcode = false;
+                                }
 
-                                    itemSvc.addCopy(cp)
-                                });
+                                itemSvc.addCopy(cp)
                             }
                         }
                     );

commit e2c10c4895f44ded8312b025c7f25e1ad46ad2d6
Author: Mike Rylander <mrylander at gmail.com>
Date:   Sun Apr 29 18:56:38 2018 -0400

    LP#1737812: Simplify holdings tranfser options
    
    Instead of providing direct actions for transfer of library, or record, or
    both, have just one volume transfer option that Does the Right Thing (tm).
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
index b89a93a..a6f269d 100644
--- a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
+++ b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
@@ -49,8 +49,10 @@
       label="[% l('Request Items') %]"></eg-grid-action>
     <eg-grid-action handler="attach_to_peer_bib"
       label="[% l('Link as Conjoined to Previously Marked Bib Record') %]"></eg-grid-action>
+<!--
     <eg-grid-action handler="markLibAsVolTarget"
       label="[% l('Choose Library for Volume/Copy Transfer Destination') %]"></eg-grid-action>
+-->
 
     <eg-grid-action handler="selectedHoldingsItemStatus" group="[% l('Show') %]"
       label="[% l('Item Status (list)') %]"></eg-grid-action>
@@ -95,14 +97,21 @@
     <eg-grid-action handler="selectedHoldingsVolCopyDelete" group="[% l('Delete') %]" disabled="copies_not_shown"
       label="[% l('Volumes and Copies') %]"></eg-grid-action>
 
+<!--
     <eg-grid-action handler="transferVolumesToRecord" group="[% l('Transfer') %]"
       label="[% l('Volumes to Previously Marked Record') %]"></eg-grid-action>
     <eg-grid-action handler="transferVolumesToLibrary" group="[% l('Transfer') %]"
       label="[% l('Volumes to Previously Marked Library') %]"></eg-grid-action>
+-->
+
     <eg-grid-action handler="transferVolumesToRecordAndLibrary" group="[% l('Transfer') %]"
-      label="[% l('Volumes to Previously Marked Record and Library') %]"></eg-grid-action>
+      label="[% l('Volumes to Previously Marked Destination') %]"></eg-grid-action>
+
+<!--
     <eg-grid-action handler="changeItemOwningLib" group="[% l('Transfer') %]"
       label="[% l('Copies to Previously Marked Library') %]"></eg-grid-action>
+-->
+
     <eg-grid-action handler="transferItems" group="[% l('Transfer') %]"
       label="[% l('Items to Previously Marked Volume') %]"></eg-grid-action>
 
diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
index 6bc7c89..4e207ea 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
@@ -445,6 +445,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         ngToast.create(egCore.strings.MARK_VOL_TARGET);
         $scope.current_voltransfer_target = $scope.record_id;
         egCore.hatch.setLocalItem('eg.cat.marked_volume_transfer_record',$scope.record_id);
+        egCore.hatch.removeLocalItem('eg.cat.volume_transfer_target');
     };
 
     $scope.markOverlay = function () {
@@ -1333,6 +1334,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     }
 
     $scope.markLibAsVolTarget = function() {
+        var recId = $scope.record_id;
         return $uibModal.open({
             templateUrl: './cat/catalog/t_choose_vol_target_lib',
             animation: true,
@@ -1348,6 +1350,10 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                         'eg.cat.volume_transfer_target',
                         org.id()
                     );
+                    egCore.hatch.setLocalItem(
+                        'eg.cat.marked_volume_transfer_record',
+                        recId
+                    );
                     $uibModalInstance.close();
                 }
                 $scope.cancel = function($event) {
@@ -1362,6 +1368,10 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
             'eg.cat.volume_transfer_target',
             $scope.holdingsGridControls.selectedItems()[0].owner_id
         );
+        egCore.hatch.setLocalItem(
+            'eg.cat.marked_volume_transfer_record',
+            $scope.record_id
+        );
         ngToast.create(egCore.strings.MARK_VOL_TARGET);
     }
 

commit 1e25174f4edf7f990a15445893cc20a7d1fbc25f
Author: Mike Rylander <mrylander at gmail.com>
Date:   Wed Apr 25 12:32:15 2018 -0400

    LP#1715697: Ability to add empty volumes
    
    Staff can add volumes to any library that is allowed to have holdings.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
index 8e3ff44..b89a93a 100644
--- a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
+++ b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
@@ -72,6 +72,8 @@
     <eg-grid-action handler="markVolAsItemTarget" group="[% l('Mark') %]" disabled="vols_not_shown"
       label="[% l('Volume as Item Transfer Destination') %]"></eg-grid-action>
 
+    <eg-grid-action handler="selectedHoldingsVolAdd" group="[% l('Add') %]"
+      label="[% l('Volumes') %]"></eg-grid-action>
     <eg-grid-action handler="selectedHoldingsCopyAdd" group="[% l('Add') %]" disabled="vols_not_shown"
       label="[% l('Copies') %]"></eg-grid-action>
     <eg-grid-action handler="selectedHoldingsVolCopyAdd" group="[% l('Add') %]"
diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
index 9109ac8..6bc7c89 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
@@ -1111,6 +1111,15 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         $scope.holdings_cb_changed(item.checkbox,item.checked);
     }
 
+    function gatherSelectedOwners () {
+        var owner_list = [];
+        angular.forEach(
+            $scope.holdingsGridControls.selectedItems(),
+            function (item) { owner_list.push(item.owner_id) }
+        );
+        return owner_list;
+    }
+
     function gatherSelectedHoldingsIds () {
         var cp_id_list = [];
         angular.forEach(
@@ -1270,18 +1279,28 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     $scope.selectedHoldingsVolCopyAdd = function () { spawnHoldingsAdd(true,false) }
     $scope.selectedHoldingsCopyAdd = function () { spawnHoldingsAdd(false,true) }
 
-    spawnHoldingsEdit = function (hide_vols,hide_copies){
+    spawnHoldingsEdit = function (hide_vols,hide_copies,add_vol){
+
+        var raw;
+        if (add_vol) {
+            raw = [{callnumber:null}];
+        } else {
+            raw = gatherSelectedEmptyVolumeIds().map(
+                function(v){ return { callnumber : v } }
+            );
+        }
+
         egCore.net.request(
             'open-ils.actor',
             'open-ils.actor.anon_cache.set_value',
             null, 'edit-these-copies', {
                 record_id: $scope.record_id,
                 copies: gatherSelectedHoldingsIds(),
-                raw: gatherSelectedEmptyVolumeIds().map(
-                    function(v){ return { callnumber : v } }
-                ),
+                raw: raw,
                 hide_vols : hide_vols,
-                hide_copies : hide_copies
+                hide_copies : hide_copies,
+                only_add_vol : ((add_vol) ? true : false),
+                owners : gatherSelectedOwners()
             }
         ).then(function(key) {
             if (key) {
@@ -1296,6 +1315,8 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
     $scope.selectedHoldingsVolEdit = function () { spawnHoldingsEdit(false,true) }
     $scope.selectedHoldingsCopyEdit = function () { spawnHoldingsEdit(true,false) }
 
+    $scope.selectedHoldingsVolAdd = function () { spawnHoldingsEdit(false,true,true) }
+
     $scope.selectedHoldingsItemStatus = function (){
         var url = egCore.env.basePath + 'cat/item/search/' + gatherSelectedHoldingsIds().join(',')
         $timeout(function() { $window.open(url, '_blank') });
diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js b/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
index 2fa67b4..0decd88 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
@@ -354,6 +354,15 @@ function(egCore , $q) {
                     }
                 });
 
+                function gatherSelectedOwners () {
+                    var owner_list = [];
+                    angular.forEach(
+                        $scope.holdingsGridControls.selectedItems(),
+                        function (item) { owner_list.push(item.owner_id) }
+                    );
+                    return owner_list;
+                }
+
                 function gatherHoldingsIds () {
                     var cp_id_list = [];
                     angular.forEach(
@@ -363,7 +372,7 @@ function(egCore , $q) {
                     return cp_id_list;
                 }
 
-                var spawn_volume_editor = function (copies_too) {
+                var spawn_volume_editor = function (copies_too,add_vol) {
                     egCore.net.request(
                         'open-ils.actor',
                         'open-ils.actor.anon_cache.set_value',
@@ -371,7 +380,9 @@ function(egCore , $q) {
                             record_id: $scope.recordId,
                             copies: gatherHoldingsIds(),
                             hide_vols : false,
-                            hide_copies : ((copies_too) ? false : true)
+                            hide_copies : ((copies_too) ? false : true),
+                            only_add_vol : ((add_vol) ? true : false),
+                            owners : gatherSelectedOwners()
                         }
                     ).then(function(key) {
                         if (key) {
@@ -392,11 +403,14 @@ function(egCore , $q) {
                         }
                     });
                 }
+                $scope.add_emtpy_volumes = function() {
+                    spawn_volume_editor(false,true);
+                }
                 $scope.edit_volumes = function() {
-                    spawn_volume_editor(false);
+                    spawn_volume_editor(false,false);
                 }
                 $scope.edit_copies = function() {
-                    spawn_volume_editor(true);
+                    spawn_volume_editor(true,false);
                 }
 
                 function load_holdings() {
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 e7b514b..e98bde7 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
@@ -1292,11 +1292,19 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
         ).then(function (data) {
 
             if (data) {
+                var owners = [ egCore.auth.user().ws_ou() ];
+
                 if (data.hide_vols && !$scope.defaults.always_volumes) $scope.show_vols = false;
                 if (data.hide_copies) {
                     $scope.show_copies = false;
                     $scope.only_vols = true;
                 }
+                if (data.only_add_vol) {
+                    $scope.only_add_vol = true;
+                    $scope.only_vols = true;
+                    $scope.show_copies = false;
+                    owners = data.owners;
+                }
 
                 $scope.record_id = data.record_id;
 
@@ -1339,63 +1347,64 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                                     itemSvc.addCopy(cp)
                                 });
                             } else {
-                                var cn = new egCore.idl.acn();
-                                cn.id( --itemSvc.new_cn_id );
-                                cn.isnew( true );
-                                cn.prefix( $scope.defaults.prefix || -1 );
-                                cn.suffix( $scope.defaults.suffix || -1 );
-                                cn.owning_lib( proto.owner || egCore.auth.user().ws_ou() );
-                                cn.record( $scope.record_id );
-                                egCore.org.settings(
-                                    ['cat.default_classification_scheme'],
-                                    cn.owning_lib()
-                                ).then(function (val) {
-                                    cn.label_class(
-                                        $scope.defaults.classification ||
-                                        val['cat.default_classification_scheme'] ||
-                                        1
-                                    );
-                                    if (proto.label) {
-                                        cn.label( proto.label );
-                                    } else {
-                                        egCore.net.request(
-                                            'open-ils.cat',
-                                            'open-ils.cat.biblio.record.marc_cn.retrieve',
-                                            $scope.record_id,
-                                            cn.label_class()
-                                        ).then(function(cn_array) {
-                                            if (cn_array.length > 0) {
-                                                for (var field in cn_array[0]) {
-                                                    cn.label( cn_array[0][field] );
-                                                    break;
+                                angular.forEach(owners, function(owner) {
+                                    var cn = new egCore.idl.acn();
+                                    cn.id( --itemSvc.new_cn_id );
+                                    cn.isnew( true );
+                                    cn.prefix( $scope.defaults.prefix || -1 );
+                                    cn.suffix( $scope.defaults.suffix || -1 );
+                                    cn.owning_lib( owner );
+                                    cn.record( $scope.record_id );
+                                    egCore.org.settings(
+                                        ['cat.default_classification_scheme'],
+                                        cn.owning_lib()
+                                    ).then(function (val) {
+                                        cn.label_class(
+                                            $scope.defaults.classification ||
+                                            val['cat.default_classification_scheme'] ||
+                                            1
+                                        );
+                                        if (proto.label) {
+                                            cn.label( proto.label );
+                                        } else {
+                                            egCore.net.request(
+                                                'open-ils.cat',
+                                                'open-ils.cat.biblio.record.marc_cn.retrieve',
+                                                $scope.record_id,
+                                                cn.label_class()
+                                            ).then(function(cn_array) {
+                                                if (cn_array.length > 0) {
+                                                    for (var field in cn_array[0]) {
+                                                        cn.label( cn_array[0][field] );
+                                                        break;
+                                                    }
                                                 }
-                                            }
-                                        });
-                                    }
-                                });
+                                            });
+                                        }
+                                    });
 
-                                var cp = new itemSvc.generateNewCopy(
-                                    cn,
-                                    proto.owner || egCore.auth.user().ws_ou(),
-                                    $scope.is_fast_add,
-                                    true
-                                );
+                                    var cp = new itemSvc.generateNewCopy(
+                                        cn,
+                                        proto.owner || egCore.auth.user().ws_ou(),
+                                        $scope.is_fast_add,
+                                        true
+                                    );
 
-                                if (proto.barcode) {
-                                    cp.barcode( proto.barcode );
-                                    cp.empty_barcode = false;
-                                }
+                                    if (proto.barcode) {
+                                        cp.barcode( proto.barcode );
+                                        cp.empty_barcode = false;
+                                    }
 
-                                itemSvc.addCopy(cp)
+                                    itemSvc.addCopy(cp)
+                                });
                             }
-    
                         }
                     );
 
                     return itemSvc.copies;
                 }
 
-                if (data.copies && data.copies.length)
+                if (!$scope.only_add_vol && data.copies && data.copies.length)
                     return itemSvc.fetchIds(data.copies).then(fetchRaw);
 
                 return fetchRaw();
@@ -1410,16 +1419,24 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
         $scope.can_save = false;
         function check_saveable () {
             var can_save = true;
+
             angular.forEach(
                 itemSvc.copies,
                 function (i) {
-                    if (i.duplicate_barcode || i.empty_barcode || i.call_number().empty_label)
+                    if (!$scope.only_add_vol) {
+                        if (i.duplicate_barcode || i.empty_barcode || i.call_number().empty_label) {
+                            can_save = false;
+                        }
+                    } else if (i.call_number().empty_label) {
                         can_save = false;
+                    }
                 }
             );
+
             if ($scope.forms.myForm && $scope.forms.myForm.$invalid) {
                 can_save = false;
             }
+
             $scope.can_save = can_save;
         }
 
@@ -1709,9 +1726,15 @@ function($scope , $q , $window , $routeParams , $location , $timeout , egCore ,
                     cnHash[cn_id].suffix(cnHash[cn_id].suffix().id()); // un-object-ize some fields
             });
 
-            angular.forEach(perCnCopies, function (v, k) {
-                cnHash[k].copies(v);
-            });
+            if ($scope.only_add_vol) { // strip off copies when we're in add-empty-vol mode
+                angular.forEach(cnHash, function (v, k) {
+                    cnHash[k].copies([]);
+                });
+            } else {
+                angular.forEach(perCnCopies, function (v, k) {
+                    cnHash[k].copies(v);
+                });
+            }
 
             cnList = [];
             angular.forEach(cnHash, function (v, k) {

commit e7b47284745afbba8e07ef6deaf8c02be549b522
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Apr 24 15:21:37 2018 -0400

    LP#1715697 & 1738242 & 1753005: Holdings Filtering Checkboxes
    
    When the appropriate checkbox is selected, display subordinate libraries of
    the context library that do not have any holdings or empty volumes.
    
    Additionally, the holdings view checkboxes for limiting detail display can
    cause console alerts, and should be made visually interdependent.  This commit
    addresses both of those issues.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Jason Stephenson <jason at sigio.com>
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>

diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
index b506f3f..8e3ff44 100644
--- a/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
+++ b/Open-ILS/src/templates/staff/cat/catalog/t_holdings.tt2
@@ -18,11 +18,16 @@
     grid-controls="holdingsGridControls"
     persist-key="cat.holdings">
 
-     <eg-grid-menu-item handler="holdings_checkbox_handler"
+    <eg-grid-menu-item handler="holdings_checkbox_handler"
       label="[% l('Show empty volumes') %]"
       checkbox="holdings_show_empty"
       checked="holdings_show_empty"/>
- 
+
+    <eg-grid-menu-item handler="holdings_checkbox_handler"
+      label="[% l('Show empty libraries') %]"
+      checkbox="holdings_show_empty_org"
+      checked="holdings_show_empty_org"/>
+
     <eg-grid-menu-item handler="holdings_checkbox_handler"
       label="[% l('Show copy detail') %]"
       checkbox="holdings_show_copies"
diff --git a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
index e7ef534..9109ac8 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
@@ -1028,9 +1028,10 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         holdingsSvcInst.fetch({
             rid : $scope.record_id,
             org : $scope.holdings_ou,
-            copy: $scope.holdings_show_copies,
+            copy: $scope.holdings_show_vols ? $scope.holdings_show_copies : false,
             vol : $scope.holdings_show_vols,
-            empty: $scope.holdings_show_empty
+            empty: $scope.holdings_show_empty,
+            empty_org: $scope.holdings_show_empty_org
         }).then(function() {
             $scope.holdingsGridDataProvider.refresh();
         });
@@ -1043,9 +1044,10 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         holdingsSvcInst.fetch({
             rid : $scope.record_id,
             org : $scope.holdings_ou,
-            copy: $scope.holdings_show_copies,
+            copy: $scope.holdings_show_vols ? $scope.holdings_show_copies : false,
             vol : $scope.holdings_show_vols,
-            empty: $scope.holdings_show_empty
+            empty: $scope.holdings_show_empty,
+            empty_org: $scope.holdings_show_empty_org
         }).then(function() {
             $scope.holdingsGridDataProvider.refresh();
         });
@@ -1053,13 +1055,16 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
 
     $scope.holdings_cb_changed = function(cb,newVal,norefresh) {
         $scope[cb] = newVal;
+        var x = $scope.holdings_show_vols ? $scope.holdings_show_copies : false;
+        $('#holdings_show_copies').prop('checked', x);
         egCore.hatch.setItem('cat.' + cb, newVal);
         if (!norefresh) holdingsSvcInst.fetch({
             rid : $scope.record_id,
             org : $scope.holdings_ou,
-            copy: $scope.holdings_show_copies,
+            copy: $scope.holdings_show_vols ? $scope.holdings_show_copies : false,
             vol : $scope.holdings_show_vols,
-            empty: $scope.holdings_show_empty
+            empty: $scope.holdings_show_empty,
+            empty_org: $scope.holdings_show_empty_org
         }).then(function() {
             $scope.holdingsGridDataProvider.refresh();
         });
@@ -1073,12 +1078,19 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         egCore.hatch.getItem('cat.holdings_show_copies').then(function(x){
             if (typeof x ==  'undefined') x = true;
             $scope.holdings_cb_changed('holdings_show_copies',x,true);
+            x = $scope.holdings_show_vols ? x : false;
             $('#holdings_show_copies').prop('checked', x);
         }).then(function(){
             egCore.hatch.getItem('cat.holdings_show_empty').then(function(x){
                 if (typeof x ==  'undefined') x = true;
                 $scope.holdings_cb_changed('holdings_show_empty',x);
                 $('#holdings_show_empty').prop('checked', x);
+            }).then(function(){
+                egCore.hatch.getItem('cat.holdings_show_empty_org').then(function(x){
+                    if (typeof x ==  'undefined') x = true;
+                    $scope.holdings_cb_changed('holdings_show_empty_org',x);
+                    $('#holdings_show_empty_org').prop('checked', x);
+                })
             })
         })
     });
@@ -1091,6 +1103,10 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
         return !$scope.holdings_show_copies;
     }
 
+    $scope.empty_org_not_shown = function () {
+        return !$scope.holdings_show_empty_org;
+    }
+
     $scope.holdings_checkbox_handler = function (item) {
         $scope.holdings_cb_changed(item.checkbox,item.checked);
     }
diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js b/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
index 3f4ec7d..2fa67b4 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/holdings.js
@@ -26,7 +26,8 @@ function(egCore , $q) {
             org: this.org,
             copy: this.copy,
             vol: this.vol,
-            empty: this.empty
+            empty: this.empty,
+            empty_org: this.empty_org
         })
     };
 
@@ -41,6 +42,7 @@ function(egCore , $q) {
         }
 
         var rid = opts.rid;
+        var empty_org = opts.empty_org;
         var org = opts.org;
         var copy = opts.copy;
         var vol = opts.vol;
@@ -52,6 +54,7 @@ function(egCore , $q) {
         svc.ongoing = true;
 
         svc.rid = rid;
+        svc.empty_org = opts.empty_org;
         svc.org = org;
         svc.copy = opts.copy;
         svc.vol = opts.vol;
@@ -63,6 +66,9 @@ function(egCore , $q) {
         var org_list = egCore.org.descendants(org.id(), true);
         console.log('Holdings fetch with: rid='+rid+' org='+org_list+' copy='+copy+' vol='+vol+' empty='+empty);
 
+        svc.org_use_map = {};
+        org_list.map(function(o){svc.org_use_map[''+o]=0;})
+
         var p = egCore.pcrud.search(
             'acn',
             {record : rid, owning_lib : org_list, deleted : 'f'},
@@ -70,6 +76,7 @@ function(egCore , $q) {
         ).then(
             function() { // finished
                 if (p.cancel) return;
+
                 svc.copies = svc.copies.sort(
                     function (a, b) {
                         function compare_array (x, y, i) {
@@ -204,7 +211,10 @@ function(egCore , $q) {
                                     current_blob.cn_count++;
                                     current_blob.copy_count += cp.copy_count;
                                     current_blob.id_list = current_blob.id_list.concat(cp.id_list);
-                                    if (cp.raw) current_blob.raw = current_blob.raw.concat(cp.raw);
+                                    if (cp.raw) {
+                                        if (current_blob.raw) current_blob.raw = current_blob.raw.concat(cp.raw);
+                                        else current_blob.raw = cp.raw;
+                                    }
                                 } else {
                                     current_blob.barcode = current_blob.copy_count;
                                     current_blob.call_number = { label : current_blob.cn_count };
@@ -231,6 +241,40 @@ function(egCore , $q) {
                     }
                 }
 
+                if (empty_org) {
+
+                    var empty_org_list = [];
+                    angular.forEach(svc.org_use_map,function(v,k){
+                        if (v == 0) empty_org_list.push(k);
+                    });
+
+                    angular.forEach(empty_org_list, function (oid) {
+                        var owner = egCore.org.get(oid);
+                        if (owner.ou_type().can_have_vols() != 't') return;
+
+                        var owner_list = [];
+                        while (owner.parent_ou()) { // we're going to skip the top of the tree...
+                            owner_list.unshift(owner.shortname());
+                            owner = egCore.org.get(owner.parent_ou());
+                        }
+
+                        var owner_label = owner_list.join(' ... ');
+
+                        new_list.push({
+                            index      : index++,
+                            id_list    : [],
+                            call_number: { label : '' },
+                            barcode    : '',
+                            owner_id   : oid,
+                            owner_list : owner_list,
+                            owner_label: owner_label,
+                            copy_count : 0,
+                            cn_count   : 0,
+                            copy_alert_count : 0
+                        });
+                    });
+                }
+
                 svc.copies = new_list;
                 svc.ongoing = false;
             },
@@ -250,6 +294,7 @@ function(egCore , $q) {
 
                 var owner_id = cn.owning_lib();
                 var owner = egCore.org.get(owner_id);
+                svc.org_use_map[''+owner_id] += 1;
 
                 var owner_name_list = [];
                 while (owner.parent_ou()) { // we're going to skip the top of the tree...

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/src/templates/staff/cat/catalog/index.tt2 |    5 +-
 .../src/templates/staff/cat/catalog/t_catalog.tt2  |    8 +-
 .../src/templates/staff/cat/catalog/t_holdings.tt2 |   33 ++--
 .../web/js/ui/default/staff/cat/bucket/copy/app.js |    2 +-
 .../web/js/ui/default/staff/cat/catalog/app.js     |  236 ++++++++++----------
 .../js/ui/default/staff/cat/services/holdings.js   |   49 ++++-
 .../web/js/ui/default/staff/cat/volcopy/app.js     |   48 +++--
 .../web/js/ui/default/staff/circ/services/item.js  |   19 +-
 8 files changed, 229 insertions(+), 171 deletions(-)


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list