webstaff: implement patron merge interface
authorGalen Charlton <gmc@esilibrary.com>
Tue, 25 Oct 2016 21:23:13 +0000 (17:23 -0400)
committerKathy Lussier <klussier@masslnc.org>
Tue, 22 Nov 2016 19:10:04 +0000 (14:10 -0500)
This patch adds a 'Merge Patrons' button to the patron
search grid. If the user selects two patron records, the
button can be clicked to present a dialog that allows
the user to pick a lead record and confirm a merge of the
patrons.

This patch also adds an egPatronSummary directive that
uses the existing patron summary template with a couple
modifications.

Signed-off-by: Galen Charlton <gmc@esilibrary.com>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Open-ILS/src/templates/staff/circ/patron/index.tt2
Open-ILS/src/templates/staff/circ/patron/t_search_results.tt2
Open-ILS/src/templates/staff/circ/patron/t_summary.tt2
Open-ILS/web/js/ui/default/staff/circ/patron/app.js
Open-ILS/web/js/ui/default/staff/circ/services/patrons.js [new file with mode: 0644]

index 810950d..ebde904 100644 (file)
@@ -11,6 +11,7 @@
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/eframe.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/date.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/patrons.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/billing.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/circ.js"></script>
 [% INCLUDE 'staff/circ/share/circ_strings.tt2' %]
index f7378f7..a5a58af 100644 (file)
   grid-controls="gridControls"
   items-provider="patronSearchGridProvider"
   persist-key="circ.patron.search">
+
+  <eg-grid-menu-item handler="merge_patrons"
+    disabled="need_two_selected"
+    label="[% l('Merge Patrons') %]"></eg-grid-menu-item>
+
   <eg-grid-field label="[% ('ID') %]" path='id' visible></eg-grid-field>
   <eg-grid-field label="[% ('Card') %]" path='card.barcode' visible></eg-grid-field>
   <eg-grid-field label="[% ('Profile') %]" path='profile.name' visible></eg-grid-field>
index 83a5957..606687d 100644 (file)
       <div class="col-md-5">[% l('Profile') %]</div>
       <div class="col-md-7">{{patron().profile().name()}}</div>
     </div>
+    <div class="row" ng-if="show_name()">
+      <div class="col-md-5">[% l('ID') %]</div>
+      <div class="col-md-7">{{patron().id()}}</div>
+    </div>
+    <div class="row" ng-if="show_name()">
+      <div class="col-md-5">[% l('Name') %]</div>
+      <div class="col-md-7">
+                    [% l('[_1], [_2] [_3]',
+                '{{patron().family_name()}}',
+                '{{patron().first_given_name()}}',
+                '{{patron().second_given_name()}}') %]
+      </div>
+    </div>
     <div class="row">
       <div class="col-md-5">[% l('Home Library') %]</div>
       <div class="col-md-7">{{patron().home_ou().shortname()}}</div>
index 31b2358..bb514c4 100644 (file)
@@ -789,8 +789,10 @@ function($scope , $location , egCore , egConfirmDialog , egUser , patronSvc) {
 .controller('PatronSearchCtrl',
        ['$scope','$q','$routeParams','$timeout','$window','$location','egCore',
        '$filter','egUser', 'patronSvc','egGridDataProvider','$document',
+       'egPatronMerge',
 function($scope,  $q,  $routeParams,  $timeout,  $window,  $location,  egCore,
-        $filter,  egUser,  patronSvc , egGridDataProvider , $document) {
+        $filter,  egUser,  patronSvc , egGridDataProvider , $document,
+        egPatronMerge) {
 
     $scope.initTab('search');
     $scope.focusMe = true;
@@ -1080,6 +1082,27 @@ function($scope,  $q,  $routeParams,  $timeout,  $window,  $location,  egCore,
         // force the grid to load the url-based search on page load
         provider.refresh();
     }
+
+    $scope.need_two_selected = function() {
+        var items = $scope.gridControls.selectedItems();
+        return (items.length == 2) ? false : true;
+    }
+    $scope.merge_patrons = function() {
+        var items = $scope.gridControls.selectedItems();
+        if (items.length != 2) return false;
+
+        var patron_ids = [];
+        angular.forEach(items, function(i) {
+            patron_ids.push(i.id());
+        });
+        egPatronMerge.do_merge(patron_ids).then(function() {
+            // ensure that we're not drawing from cached
+            // resuts, as a successful merge just deleted a
+            // record
+            delete patronSvc.lastSearch;
+            $scope.gridControls.refresh();
+        });
+    }
    
 }])
 
diff --git a/Open-ILS/web/js/ui/default/staff/circ/services/patrons.js b/Open-ILS/web/js/ui/default/staff/circ/services/patrons.js
new file mode 100644 (file)
index 0000000..08e5548
--- /dev/null
@@ -0,0 +1,89 @@
+angular.module('egCoreMod')
+
+.factory('egPatronMerge',
+       ['$uibModal','$q','egCore',
+function($uibModal , $q , egCore) {
+
+    var service = {};
+
+    service.do_merge = function(patron_ids) {
+        var deferred = $q.defer();
+        $uibModal.open({
+            templateUrl: './circ/share/t_merge_patrons',
+            size: 'lg',
+            windowClass: 'eg-wide-modal',
+            controller:
+                ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
+                    $scope.lead_id = 0;
+                    $scope.patron_ids = patron_ids;
+                    $scope.ok = function() {
+                        $uibModalInstance.close({ lead_id : $scope.lead_id });
+                    }
+                    $scope.cancel = function () { $uibModalInstance.dismiss() }
+                }]
+        }).result.then(function (args) {
+            if (args.lead_id == 0) return;
+            var sub_id = (args.lead_id == patron_ids[0]) ?
+                patron_ids[1] :
+                patron_ids[0];
+            egCore.net.request(
+                'open-ils.actor',
+                'open-ils.actor.user.merge',
+                egCore.auth.token(),
+                args.lead_id,
+                [ sub_id ]
+            ).then(function(resp) {
+                var evt = egCore.evt.parse(resp);
+                if (evt) {
+                    console.debug(evt);
+                    deferred.reject(evt);
+                    return;
+                } else {
+                    deferred.resolve(); 
+                }
+            });
+        });
+        return deferred.promise;
+    }
+
+    return service;
+
+}])
+
+.directive('egPatronSummary', ['egUser','patronSvc', function(egUser, patronSvc) {
+    return {
+        restrict : 'E',
+        transclude: true,
+        templateUrl : './circ/patron/t_summary',
+        scope : {
+            patronId : '='
+        },
+        controller : [
+                    '$scope','egCore',
+            function($scope , egCore) {
+                var user;
+                var user_stats;
+                egUser.get($scope.patronId).then(function(u) {
+                    user = u;
+                    patronSvc.localFlesh(user);
+                });
+                patronSvc.getUserStats($scope.patronId).then(function(s) {
+                    user_stats = s;
+                });
+                $scope.patron = function() {
+                    return user;
+                }
+                $scope.patron_stats = function() {
+                    return user_stats;
+                }
+
+                // needed because this directive shares a template with
+                // the patron summary in circ app, but the circ app
+                // displays the patron name elsewhere. 
+                $scope.show_name = function() {
+                    return true;
+                }
+            }
+        ]
+    }
+}]);