* Search, checkout, items out, holds, bills, edit, etc.
*/
- angular.module('egPatronApp', ['ngRoute', 'ui.bootstrap',
-angular.module('egPatronApp', ['ngRoute', 'ui.bootstrap', 'egUserBucketMod',
- 'egCoreMod', 'egUiMod', 'egGridMod', 'egUserMod', 'ngToast'])
++angular.module('egPatronApp', ['ngRoute', 'ui.bootstrap', 'egUserBucketMod',
+ 'egCoreMod', 'egUiMod', 'egGridMod', 'egUserMod', 'ngToast',
+ 'egPatronSearchMod'])
.config(['ngToastProvider', function(ngToastProvider) {
ngToastProvider.configure({
* Manages patron search
*/
.controller('PatronSearchCtrl',
- ['$scope','$q','$routeParams','$timeout','$window','$location','egCore',
- '$filter','egUser', 'patronSvc','egGridDataProvider','$document',
- 'egPatronMerge','egProgressDialog','$controller',
- function($scope, $q, $routeParams, $timeout, $window, $location, egCore,
- $filter, egUser, patronSvc , egGridDataProvider , $document,
- egPatronMerge , egProgressDialog, $controller) {
+ ['$scope','$q','$routeParams','$timeout','$window','$location','egCore','ngToast',
+ '$filter','egUser', 'patronSvc','egGridDataProvider','$document','bucketSvc',
- 'egPatronMerge','egProgressDialog','$interpolate','$uibModal',
++ 'egPatronMerge','egProgressDialog','$interpolate','$uibModal','$controller',
+ function($scope, $q, $routeParams, $timeout, $window, $location, egCore , ngToast,
+ $filter, egUser, patronSvc , egGridDataProvider , $document , bucketSvc,
- egPatronMerge , egProgressDialog , $interpolate , $uibModal) {
++ egPatronMerge , egProgressDialog , $interpolate , $uibModal , $controller) {
+ angular.extend(this, $controller('BasePatronSearchCtrl', {$scope : $scope}));
$scope.initTab('search');
- $scope.focusMe = true;
- $scope.searchArgs = {
- // default to searching globally
- home_ou : egCore.org.tree()
- };
-
- // last used patron search form element
- var lastFormElement;
$scope.gridControls = {
activateItem : function(item) {
$location.path('/circ/patron/' + item.id() + '/checkout');
},
- selectedItems : function() {return []}
+ selectedItems : function() { return [] }
+ }
+
+ $scope.bucketSvc = bucketSvc;
+ $scope.bucketSvc.fetchUserBuckets();
+ $scope.addToBucket = function(item, data, recs) {
+ if (recs.length == 0) return;
+ var added_count = 0;
+ var failed_count = 0;
+ var p = [];
+ angular.forEach(recs,
+ function(rec) {
+ var item = new egCore.idl.cubi();
+ item.bucket(data.id());
+ item.target_user(rec.id());
+ p.push(egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.container.item.create',
+ egCore.auth.token(), 'user', item
+ ).then(
+ function(){ added_count++ },
+ function(){ failed_count++ }
+ ));
+ }
+ );
+
+ $q.all(p).then( function () {
+ if (added_count) ngToast.create($interpolate(egCore.strings.BUCKET_ADD_SUCCESS)({ count: ''+added_count, name: data.name()} ));
+ if (failed_count) ngToast.warning($interpolate(egCore.strings.BUCKET_ADD_FAIL)({ count: ''+failed_count, name: data.name() } ));
+ });
+ }
+
+ var temp_scope = $scope;
+ $scope.openCreateBucketDialog = function() {
+ $uibModal.open({
+ templateUrl: './circ/patron/bucket/t_bucket_create',
+ controller:
+ ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
+ $scope.focusMe = true;
+ $scope.ok = function(args) { $uibModalInstance.close(args) }
+ $scope.cancel = function () { $uibModalInstance.dismiss() }
+ }]
+ }).result.then(function (args) {
+ if (!args || !args.name) return;
+ bucketSvc.createBucket(args.name, args.desc).then(
+ function(id) {
+ if (id) {
+ $scope.bucketSvc.fetchBucket(id).then(function (b) {
+ $scope.addToBucket(
+ null,
+ b,
+ $scope.gridControls.selectedItems()
+ );
+ $scope.bucketSvc.fetchUserBuckets(true);
+ });
+ }
+ }
+ );
+ });
}
- // Handle URL-encoded searches
- if ($location.search().search) {
- console.log('URL search = ' + $location.search().search);
- patronSvc.urlSearch = {search : JSON2js($location.search().search)};
-
- // why the double-JSON encoded sort?
- if (patronSvc.urlSearch.search.search_sort) {
- patronSvc.urlSearch.sort =
- JSON2js(patronSvc.urlSearch.search.search_sort);
- } else {
- patronSvc.urlSearch.sort = [];
- }
- delete patronSvc.urlSearch.search.search_sort;
-
- // include inactive patrons if "inactive" param
- if ($location.search().inactive) {
- patronSvc.urlSearch.inactive = $location.search().inactive;
- }
- }
-
- var propagate;
- var propagate_inactive;
- if (patronSvc.lastSearch) {
- propagate = patronSvc.lastSearch.search;
- // home_ou needs to be treated specially
- propagate.home_ou = {
- value : patronSvc.lastSearch.home_ou,
- group : 0
- };
- } else if (patronSvc.urlSearch) {
- propagate = patronSvc.urlSearch.search;
- if (patronSvc.urlSearch.inactive) {
- propagate_inactive = patronSvc.urlSearch.inactive;
- }
- }
-
- if (egCore.env.pgt) {
- $scope.profiles = egCore.env.pgt.list;
- } else {
- egCore.pcrud.search('pgt', {parent : null},
- {flesh : -1, flesh_fields : {pgt : ['children']}}
- ).then(
- function(tree) {
- egCore.env.absorbTree(tree, 'pgt')
- $scope.profiles = egCore.env.pgt.list;
- }
- );
- }
-
- if (propagate) {
- // populate the search form with our cached / preexisting search info
- angular.forEach(propagate, function(val, key) {
- if (key == 'profile')
- val.value = $scope.profiles.filter(function(p) { return p.id() == val.value })[0];
- if (key == 'home_ou')
- val.value = egCore.org.get(val.value);
- $scope.searchArgs[key] = val.value;
- });
- if (propagate_inactive) {
- $scope.searchArgs.inactive = propagate_inactive;
- }
- }
-
- var provider = egGridDataProvider.instance({});
-
$scope.$watch(
function() {return $scope.gridControls.selectedItems()},
function(list) {
},
true
);
-
- provider.get = function(offset, count) {
- var deferred = $q.defer();
-
- var fullSearch;
- if (patronSvc.urlSearch) {
- fullSearch = patronSvc.urlSearch;
- // enusre the urlSearch only runs once.
- delete patronSvc.urlSearch;
-
- } else {
- patronSvc.search_barcode = $scope.searchArgs.card;
-
- var search = compileSearch($scope.searchArgs);
- if (Object.keys(search) == 0) return $q.when();
-
- var home_ou = search.home_ou;
- delete search.home_ou;
- var inactive = search.inactive;
- delete search.inactive;
-
- fullSearch = {
- search : search,
- sort : compileSort(),
- inactive : inactive,
- home_ou : home_ou,
- };
- }
-
- fullSearch.count = count;
- fullSearch.offset = offset;
-
- if (patronSvc.lastSearch) {
- // search repeated, return the cached results
- if (angular.equals(fullSearch, patronSvc.lastSearch)) {
- console.log('patron search returning ' +
- patronSvc.patrons.length + ' cached results');
-
- // notify has to happen after returning the promise
- $timeout(
- function() {
- angular.forEach(patronSvc.patrons, function(user) {
- deferred.notify(user);
- });
- deferred.resolve();
- }
- );
- return deferred.promise;
- }
- }
-
- patronSvc.lastSearch = fullSearch;
-
- if (fullSearch.search.id) {
- // search by user id performs a direct ID lookup
- var userId = fullSearch.search.id.value;
- $timeout(
- function() {
- egUser.get(userId).then(function(user) {
- patronSvc.localFlesh(user);
- patronSvc.patrons = [user];
- deferred.notify(user);
- deferred.resolve();
- });
- }
- );
- return deferred.promise;
- }
-
- if (!Object.keys(fullSearch.search).length) {
- // Empty searches are rejected by the server. Avoid
- // running the the empty search that runs on page load.
- return $q.when();
- }
-
- egProgressDialog.open(); // Indeterminate
-
- patronSvc.patrons = [];
- var which_sound = 'success';
- egCore.net.request(
- 'open-ils.actor',
- 'open-ils.actor.patron.search.advanced.fleshed',
- egCore.auth.token(),
- fullSearch.search,
- fullSearch.count,
- fullSearch.sort,
- fullSearch.inactive,
- fullSearch.home_ou,
- egUser.defaultFleshFields,
- fullSearch.offset
-
- ).then(
- function() {
- deferred.resolve();
- },
- function() { // onerror
- which_sound = 'error';
- },
- function(user) {
- // hide progress bar as soon as the first result appears.
- egProgressDialog.close();
- patronSvc.localFlesh(user); // inline
- patronSvc.patrons.push(user);
- deferred.notify(user);
- }
- )['finally'](function() { // close on 0-hits or error
- if (which_sound == 'success' && patronSvc.patrons.length == 0) {
- which_sound = 'warning';
- }
- egCore.audio.play(which_sound + '.patron.by_search');
- egProgressDialog.close();
- });
-
- return deferred.promise;
- };
-
- $scope.patronSearchGridProvider = provider;
-
- // determine the tree depth of the profile group
- $scope.pgt_depth = function(grp) {
- var d = 0;
- while (grp = egCore.env.pgt.map[grp.parent()]) d++;
- return d;
- }
-
- $scope.clearForm = function () {
- $scope.searchArgs={};
- if (lastFormElement) lastFormElement.focus();
- }
-
- $scope.applyShowExtras = function($event, bool) {
- if (bool) {
- $scope.showExtras = true;
- egCore.hatch.setItem('eg.circ.patron.search.show_extras', true);
- } else {
- $scope.showExtras = false;
- egCore.hatch.removeItem('eg.circ.patron.search.show_extras');
- }
- if (lastFormElement) lastFormElement.focus();
- $event.preventDefault();
- }
-
- egCore.hatch.getItem('eg.circ.patron.search.show_extras')
- .then(function(val) {$scope.showExtras = val});
-
- // map form arguments into search params
- function compileSearch(args) {
- var search = {};
- angular.forEach(args, function(val, key) {
- if (!val) return;
- if (key == 'profile' && args.profile) {
- search.profile = {value : args.profile.id(), group : 0};
- } else if (key == 'home_ou' && args.home_ou) {
- search.home_ou = args.home_ou.id(); // passed separately
- } else if (key == 'inactive') {
- search.inactive = val;
- } else {
- search[key] = {value : val, group : 0};
- }
- if (key.match(/phone|ident/)) {
- search[key].group = 2;
- } else {
- if (key.match(/street|city|state|post_code/)) {
- search[key].group = 1;
- } else if (key == 'card') {
- search[key].group = 3
- }
- }
- });
-
- return search;
- }
-
- function compileSort() {
-
- if (!provider.sort.length) {
- return [ // default
- "family_name ASC",
- "first_given_name ASC",
- "second_given_name ASC",
- "dob DESC"
- ];
- }
-
- var sort = [];
- angular.forEach(
- provider.sort,
- function(sortdef) {
- if (angular.isObject(sortdef)) {
- var name = Object.keys(sortdef)[0];
- var dir = sortdef[name];
- sort.push(name + ' ' + dir);
- } else {
- sort.push(sortdef);
- }
- }
- );
-
- return sort;
- }
-
- $scope.setLastFormElement = function() {
- lastFormElement = $document[0].activeElement;
- }
-
- // search form submit action; tells the results grid to
- // refresh itself.
- $scope.search = function(args) { // args === $scope.searchArgs
- if (args && Object.keys(args).length)
- $scope.gridControls.refresh();
- if (lastFormElement) lastFormElement.focus();
- }
-
- // TODO: move this into the (forthcoming) grid row activate action
- $scope.onPatronDblClick = function($event, user) {
- $location.path('/circ/patron/' + user.id() + '/checkout');
- }
-
- if (patronSvc.urlSearch) {
- // force the grid to load the url-based search on page load
- provider.refresh();
- }
+ $scope.need_one_selected = function() {
+ var items = $scope.gridControls.selectedItems();
+ return (items.length > 0) ? false : true;
+ }
$scope.need_two_selected = function() {
var items = $scope.gridControls.selectedItems();
return (items.length == 2) ? false : true;