[open-ils-commits] [GIT] Evergreen ILS branch master updated. 07475722b8b483537b8b2795a800eba5b1af36b2

Evergreen Git git at git.evergreen-ils.org
Wed Jul 18 09:42:31 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, master has been updated
       via  07475722b8b483537b8b2795a800eba5b1af36b2 (commit)
       via  cbf7073ad3ca14ce445ab19e57c51f7cdf5cc305 (commit)
       via  98a2ff8c5c279bb361690426abd5922fe55e9e12 (commit)
       via  f74185f58effccaeeeee0b7b1c39773f96733220 (commit)
       via  0ec789d66d5aa7a4d92c6e517d72c4a96688bfc1 (commit)
       via  8ee176d110c4dae5481ab9970900a7a5667ae611 (commit)
       via  77b784dd8fe189aeb3ae7e0ddaf4c434c057087c (commit)
       via  5a1d701bcc1b5b25697b03aae3bf837f6e6921f4 (commit)
      from  000623bb63fbec902f3863f3233a33aad0f24474 (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 07475722b8b483537b8b2795a800eba5b1af36b2
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: Dan Wells <dbw2 at calvin.edu>

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 c5e929b..462b5d6 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
@@ -1382,7 +1382,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
@@ -1401,7 +1401,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)
                                     );
@@ -1456,7 +1456,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 cbf7073ad3ca14ce445ab19e57c51f7cdf5cc305
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.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Mike Rylander <mrylander at gmail.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 2980123..f188a1a 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>
@@ -101,23 +94,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 f6ccffb..3208a42 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
@@ -725,7 +725,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 c3505ab..203bb71 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
@@ -377,7 +377,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 () {
@@ -443,11 +443,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 () {
@@ -458,10 +459,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');
@@ -1314,57 +1315,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',
-            backdrop: 'static',
-            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 (){
@@ -1378,20 +1348,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) {
@@ -1417,54 +1402,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 {
@@ -1474,7 +1440,7 @@ function($scope , $routeParams , $location , $window , $q , egCore , egHolds , e
                 }
             }
         });
-    
+
         var promises = [];
         angular.forEach(vols_to_move, function(vol) {
             promises.push(egCore.net.request(
@@ -1482,8 +1448,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
@@ -1515,9 +1481,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 d931d3a..aaed14d 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
@@ -779,7 +779,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;
         }
@@ -804,7 +804,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',
@@ -823,24 +823,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 98a2ff8c5c279bb361690426abd5922fe55e9e12
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>

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 f9ba1e7..c3505ab 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
@@ -1143,7 +1143,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)
             }
         );
@@ -1233,13 +1236,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(),
@@ -1265,8 +1268,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) {
@@ -1277,9 +1279,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 82e888d..c5e929b 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
@@ -592,7 +592,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;
@@ -722,11 +722,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);
@@ -735,6 +730,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();
@@ -1372,9 +1372,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;
 
@@ -1477,7 +1474,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();
@@ -1496,7 +1493,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;
                         }
@@ -1506,7 +1503,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;
             }
 
@@ -1796,7 +1793,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 f74185f58effccaeeeee0b7b1c39773f96733220
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>

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 0ec789d66d5aa7a4d92c6e517d72c4a96688bfc1
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>

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 30cea7b..f9ba1e7 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
@@ -1120,15 +1120,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(
@@ -1242,7 +1233,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) {
@@ -1255,7 +1246,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 {
@@ -1274,7 +1265,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) {
@@ -1285,31 +1277,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) {
@@ -1324,8 +1307,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 ec387ec..b4fb738 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
@@ -360,15 +360,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(
@@ -378,7 +369,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',
@@ -386,9 +377,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) {
@@ -410,14 +399,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 32222cf..82e888d 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
@@ -1367,8 +1367,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;
@@ -1376,9 +1374,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;
@@ -1422,56 +1417,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 8ee176d110c4dae5481ab9970900a7a5667ae611
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 545374f..2980123 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>
@@ -99,14 +101,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 fec7089..30cea7b 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
@@ -447,6 +447,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 () {
@@ -1341,6 +1342,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',
             backdrop: 'static',
@@ -1357,6 +1359,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) {
@@ -1371,6 +1377,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 77b784dd8fe189aeb3ae7e0ddaf4c434c057087c
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 222ea20..545374f 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 5debd68..fec7089 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
@@ -1119,6 +1119,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(
@@ -1278,18 +1287,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) {
@@ -1304,6 +1323,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 b4fb738..ec387ec 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
@@ -360,6 +360,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(
@@ -369,7 +378,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',
@@ -377,7 +386,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) {
@@ -399,11 +410,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 a744a0c..32222cf 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
@@ -1367,11 +1367,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;
 
@@ -1414,63 +1422,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();
@@ -1485,16 +1494,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;
         }
 
@@ -1781,9 +1798,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 5a1d701bcc1b5b25697b03aae3bf837f6e6921f4
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 c6bf4e0..222ea20 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 4b3d186..5debd68 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
@@ -1036,9 +1036,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();
         });
@@ -1051,9 +1052,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();
         });
@@ -1061,13 +1063,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();
         });
@@ -1081,12 +1086,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);
+                })
             })
         })
     });
@@ -1099,6 +1111,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 eb835f5..b4fb738 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) {
@@ -210,7 +217,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 };
@@ -237,6 +247,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;
             },
@@ -256,6 +300,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     |  237 ++++++++++----------
 .../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(+), 172 deletions(-)


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list