From fcfcba57c7e93e336bbaa62b928602606f5bfb57 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Mon, 9 Jun 2014 16:52:44 -0400 Subject: [PATCH] group member details UI; initial Signed-off-by: Bill Erickson --- Open-ILS/src/templates/staff/circ/patron/index.tt2 | 6 + .../staff/circ/patron/t_add_to_group_dialog.tt2 | 23 ++++ .../src/templates/staff/circ/patron/t_group.tt2 | 39 ++++++ .../src/templates/staff/circ/patron/t_summary.tt2 | 7 + .../web/js/ui/default/staff/circ/patron/app.js | 148 ++++++++++++++++++++- Open-ILS/web/js/ui/default/staff/services/grid.js | 23 +++- 6 files changed, 234 insertions(+), 12 deletions(-) create mode 100644 Open-ILS/src/templates/staff/circ/patron/t_add_to_group_dialog.tt2 create mode 100644 Open-ILS/src/templates/staff/circ/patron/t_group.tt2 diff --git a/Open-ILS/src/templates/staff/circ/patron/index.tt2 b/Open-ILS/src/templates/staff/circ/patron/index.tt2 index 853304f1b5..c08791da66 100644 --- a/Open-ILS/src/templates/staff/circ/patron/index.tt2 +++ b/Open-ILS/src/templates/staff/circ/patron/index.tt2 @@ -32,6 +32,7 @@ angular.module('egCoreMod').run(['egStrings', function(s) { s.CONFIRM_REFUND_PAYMENT = "[% |l('{{xactIds}}') -%]Are you sure you would like to refund excess payment on bills [_1]? This action will simply put the amount in the Payment Pending column as a negative value. You must still select Apply Payment! Certain types of payments may not be refunded. The refund may be applied to checked transactions that follow the refunded transaction.[% END %]"; s.EDIT_BILL_PAY_NOTE = "[% l('Enter new note for #[_1]:','{{ids}}') %]"; + s.GROUP_ADD_USER = "[% l('Enter the patron barcode') %]"; }]); @@ -102,6 +103,11 @@ angular.module('egCoreMod').run(['egStrings', function(s) {
  • + + [% l('Group Member Details') %] + +
  • +
  • [% l('Test Password') %] diff --git a/Open-ILS/src/templates/staff/circ/patron/t_add_to_group_dialog.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_add_to_group_dialog.tt2 new file mode 100644 index 0000000000..caa1d841f9 --- /dev/null +++ b/Open-ILS/src/templates/staff/circ/patron/t_add_to_group_dialog.tt2 @@ -0,0 +1,23 @@ +
    + + + +
    + diff --git a/Open-ILS/src/templates/staff/circ/patron/t_group.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_group.tt2 new file mode 100644 index 0000000000..9a74166547 --- /dev/null +++ b/Open-ILS/src/templates/staff/circ/patron/t_group.tt2 @@ -0,0 +1,39 @@ + +
    [% l('Group Member Details') %]
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2 index 50ba8496c4..cbbc366e9e 100644 --- a/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2 +++ b/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2 @@ -49,6 +49,13 @@ {{patron_stats().fines.balance_owed | currency}} +
    +
    [% l('Group Fines') %]
    +
    + {{patron_stats().fines.group_balance_owed | currency}} +
    +
    [% l('Items Out') %]
    {{patron_stats().checkouts.out}}
    diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/app.js b/Open-ILS/web/js/ui/default/staff/circ/patron/app.js index 1fd4db717e..c312212d0c 100644 --- a/Open-ILS/web/js/ui/default/staff/circ/patron/app.js +++ b/Open-ILS/web/js/ui/default/staff/circ/patron/app.js @@ -136,6 +136,12 @@ angular.module('egPatronApp', ['ngRoute', 'ui.bootstrap', resolve : resolver }); + $routeProvider.when('/circ/patron/:id/group', { + templateUrl: './circ/patron/t_group', + controller: 'PatronGroupCtrl', + resolve : resolver + }); + $routeProvider.otherwise({redirectTo : '/circ/patron/search'}); }) @@ -310,13 +316,25 @@ function($q , $timeout , $location , egCore, egUser , $locale) { return deferred.promise; } + service.fetchGroupFines = function() { + return egCore.net.request( + 'open-ils.actor', + 'open-ils.actor.usergroup.members.balance_owed', + egCore.auth.token(), service.current.usrgroup() + ).then(function(list) { + var total = 0; + angular.forEach(list, function(u) { + total += 100 * Number(u.balance_owed) + }); + service.patron_stats.fines.group_balance_owed = total / 100; + }); + } - // grab additional circ info - service.fetchUserStats = function() { + service.getUserStats = function(id) { return egCore.net.request( 'open-ils.actor', 'open-ils.actor.user.opac.vital_stats.authoritative', - egCore.auth.token(), service.current.id() + egCore.auth.token(), id ).then( function(stats) { // force numeric to ensure correct boolean handling in templates @@ -325,9 +343,19 @@ function($q , $timeout , $location , egCore, egUser , $locale) { stats.checkouts.claims_returned = Number(stats.checkouts.claims_returned); stats.checkouts.lost = Number(stats.checkouts.lost); - service.patron_stats = stats + return stats; } - ) + ); + } + + + // grab additional circ info + service.fetchUserStats = function() { + return service.getUserStats(service.current.id()) + .then(function(stats) { + service.patron_stats = stats + return service.fetchGroupFines(); + }); } // Avoid using parens [e.g. (1.23)] to indicate negative numbers, @@ -1072,3 +1100,113 @@ function($scope, $routeParams , $location , egCore , patronSvc , $modal) { refreshPage(); }]) +.controller('PatronGroupCtrl', + ['$scope','$routeParams','$q','$location','egCore', + 'patronSvc','$modal','egPromptDialog','egConfirmDialog', +function($scope, $routeParams , $q , $location , egCore , + patronSvc , $modal , egPromptDialog , egConfirmDialog) { + + var usr_id = $routeParams.id; + + var statsCache = {}; + var gridQuery = {}; + + $scope.gridQuery = function() {return gridQuery} + $scope.gridRevision = 0; + $scope.gridSort = ['create_date']; + $scope.gridControls = { + itemRetrieved : function(item) { + + if (statsCache[item.id]) { + item.stats = statsCache[item.id]; + } else { + // user retrieved, flesh their stats + patronSvc.getUserStats(item.id).then(function(stats) { + item.stats = statsCache[item.id] = stats; + }); + } + } + } + + $scope.initTab('other', $routeParams.id).then(function() { + // let initTab() fetch the user first so we can know the usrgroup + gridQuery = { + usrgroup : patronSvc.current.usrgroup(), + deleted : 'f' + } + }); + + $scope.removeFromGroup = function(selected) { + var promises = []; + angular.forEach(selected, function(user) { + console.debug('removing user ' + user.id + ' from group'); + + promises.push( + egCore.net.request( + 'open-ils.actor', + 'open-ils.actor.usergroup.new', + egCore.auth.token(), user.id, true + ) + ); + }); + + $q.all(promises).then(function() {$scope.gridRevision++}); + } + + function addUserToGroup(user) { + user.usrgroup(patronSvc.current.usrgroup()); + user.ischanged(true); + egCore.net.request( + 'open-ils.actor', + 'open-ils.actor.patron.update', + egCore.auth.token(), user + + ).then(function() { + $scope.gridRevision++; + }); + } + + function showMoveToGroupConfirm(barcode) { + + // find the user + egCore.pcrud.search('ac', {barcode : barcode}) + + // fetch the fleshed user + .then(function(card) { + + if (!card) return; // TODO: warn user + + egCore.pcrud.retrieve('au', card.usr()) + .then(function(user) { + user.card(card); + $modal.open({ + templateUrl: './circ/patron/t_add_to_group_dialog', + controller: [ + '$scope','$modalInstance', + function($scope , $modalInstance) { + $scope.user = user; + $scope.ok = + function(count) { $modalInstance.close() } + $scope.cancel = + function () { $modalInstance.dismiss() } + } + ] + }).result.then(function() { + addUserToGroup(user); + }); + }); + }); + } + + $scope.moveToGroup = function() { + egPromptDialog.open( + egCore.strings.GROUP_ADD_USER, '', + {ok : function(value) { + if (value) + showMoveToGroupConfirm(value); + }} + ); + } + +}]) + diff --git a/Open-ILS/web/js/ui/default/staff/services/grid.js b/Open-ILS/web/js/ui/default/staff/services/grid.js index 82f5a303f0..e47181a2be 100644 --- a/Open-ILS/web/js/ui/default/staff/services/grid.js +++ b/Open-ILS/web/js/ui/default/staff/services/grid.js @@ -1143,13 +1143,8 @@ angular.module('egGridMod', idl_field.datatype == 'link' || idl_field.datatype == 'org_unit')) { class_obj = egCore.idl.classes[idl_field['class']]; - } else { - if (path_idx < (path_parts.length - 1)) { - // we ran out of classes to hop through before - // we ran out of path components - console.error("egGrid: invalid IDL path: " + path); - } } + // else, path is not in the IDL, which is fine } if (!idl_field) return null; @@ -1224,6 +1219,20 @@ angular.module('egGridMod', gridData.select = function(items) { } + // attempts a flat field lookup first. If the column is not + // found on the top-level object, attempts a nested lookup + gridData.itemFieldValue = function(item, column) { + if (column.name in item) { + if (typeof item[column.name] == 'function') { + return item[column.name](); + } else { + return item[column.name]; + } + } else { + return gridData.nestedItemFieldValue(item, column); + } + } + gridData.flatItemFieldValue = function(item, column) { return item[column.name]; } @@ -1320,7 +1329,7 @@ angular.module('egGridMod', } ); } - provider.itemFieldValue = provider.flatItemFieldValue; + //provider.itemFieldValue = provider.flatItemFieldValue; return provider; } }; -- 2.11.0