From 8c3e76cb5a45dab8843015d977bb39c5ae31420c Mon Sep 17 00:00:00 2001 From: Kyle Huckins Date: Tue, 11 Jun 2019 23:04:42 +0000 Subject: [PATCH] lp1712861 Notices Column Picker in Patron Holds - Migrate Patorn Holds UI to utilize wide_holds API introduced in lp1712854 - Expand wide_holds API to support multiple conditional restrictions at a time, including greater_than and less_than Signed-off-by: Kyle Huckins Changes to be committed: modified: Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm modified: Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2 modified: Open-ILS/web/js/ui/default/staff/circ/patron/holds.js modified: Open-ILS/web/js/ui/default/staff/services/patron_search.js Signed-off-by: Bill Erickson Signed-off-by: Chris Sharp --- .../Application/Storage/Publisher/action.pm | 38 +++-- .../templates/staff/circ/patron/t_holds_list.tt2 | 130 +++++++++++------ .../web/js/ui/default/staff/circ/patron/holds.js | 159 ++++++++++++--------- .../js/ui/default/staff/services/patron_search.js | 1 + 4 files changed, 209 insertions(+), 119 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm index 213ed59e5a..67b6782854 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm @@ -2390,19 +2390,14 @@ SELECT h.id, h.request_time, h.capture_time, h.fulfillment_time, h.checkin_time my $real = $field_map{$r} || $r; next if ($r =~ /[^a-z_.]/); # skip obvious bad inputs - my $not = ''; + my $sel_str = ''; if (ref($$restrictions{$r}) and ref($$restrictions{$r}) =~ /HASH/) { - $not = 'NOT'; - $$restrictions{$r} = $$restrictions{$r}{not}; - } - - if (!defined($$restrictions{$r})) { - $select .= " AND $real IS $not NULL "; - } elsif (ref($$restrictions{$r})) { - $select .= " AND $real $not IN (\$_$$\$" . join("\$_$$\$,\$_$$\$", @{$$restrictions{$r}}) . "\$_$$\$)"; + for my $rkey (keys %$restrictions{$r}) { + $sel_str .= handle_wide_hold_restrictions($$restrictions{$r}{$rkey}, $real, $rkey); + } + $select .= $sel_str; } else { - $not = '!' if $not; - $select .= " AND $real $not= \$_$$\$$$restrictions{$r}\$_$$\$"; + $select .= handle_wide_hold_restrictions($$restrictions{$r}, $real, ''); } $restricted++; @@ -2435,6 +2430,27 @@ SELECT h.id, h.request_time, h.capture_time, h.fulfillment_time, h.checkin_time $client->respond_complete; } + +sub handle_wide_hold_restrictions { + my $restriction = shift; + my $real = shift; + my $rkey = shift; + my $rkey_str = ''; + + $rkey_str = $rkey if $rkey eq 'not'; + + if (!defined($restriction)) { + return " AND $real IS $rkey_str NULL "; + } elsif (ref($restriction)) { + return " AND $real $rkey_str IN (\$_$$\$" . join("\$_$$\$,\$_$$\$", @{$restriction}) . "\$_$$\$)"; + } else { + $rkey_str = '!' if $rkey eq 'not'; + $rkey_str = '>' if $rkey eq 'greater_than'; + $rkey_str = '<' if $rkey eq 'less_than'; + return " AND $real $rkey_str= \$_$$\$$restriction\$_$$\$"; + } +} + __PACKAGE__->register_method( api_name => 'open-ils.storage.action.live_holds.wide_hash', api_level => 1, diff --git a/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2 index 48700fcc22..b1635fcfba 100644 --- a/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2 +++ b/Open-ILS/src/templates/staff/circ/patron/t_holds_list.tt2 @@ -2,7 +2,7 @@ id-field="id" features="clientsort,allowAll" items-provider="gridDataProvider" - persist-key="circ.patron.holds" + persist-key="circ.patron.wide_holds" dateformat="{{$root.egDateAndTimeFormat}}"> - - - - - - - - - - - - - - - - - {{item.hold.current_copy().barcode()}} + + {{item.hold.cp_barcode}} - - - - + + + + - + - - - {{item.mvr.title()}} + + + {{item.hold.title}} - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js b/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js index c3ce75be85..85b66b4768 100644 --- a/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js +++ b/Open-ILS/web/js/ui/default/staff/circ/patron/holds.js @@ -4,9 +4,9 @@ angular.module('egPatronApp').controller('PatronHoldsCtrl', - ['$scope','$q','$routeParams','egCore','egUser','patronSvc', + ['$scope','$q','$routeParams','egCore','egUser','patronSvc','egProgressDialog', 'egGridDataProvider','egHolds','$window','$location','egCirc','egHoldGridActions', -function($scope, $q, $routeParams, egCore, egUser, patronSvc, +function($scope, $q, $routeParams, egCore, egUser, patronSvc, egProgressDialog, egGridDataProvider , egHolds , $window , $location , egCirc, egHoldGridActions) { $scope.initTab('holds', $routeParams.id); @@ -18,6 +18,7 @@ function($scope, $q, $routeParams, egCore, egUser, patronSvc, patronSvc.refreshPrimary(); patronSvc.holds = []; patronSvc.hold_ids = []; + patronSvc.hold_count = 0; provider.refresh() } $scope.grid_actions.refresh = refresh_all; @@ -27,6 +28,7 @@ function($scope, $q, $routeParams, egCore, egUser, patronSvc, $scope.holds_display = 'main'; patronSvc.holds = []; patronSvc.hold_ids = []; + patronSvc.hold_count = 0; provider.refresh(); } @@ -35,6 +37,7 @@ function($scope, $q, $routeParams, egCore, egUser, patronSvc, $scope.holds_display = 'alt'; patronSvc.holds = []; patronSvc.hold_ids = []; + patronSvc.hold_count = 0; provider.refresh(); } @@ -49,22 +52,20 @@ function($scope, $q, $routeParams, egCore, egUser, patronSvc, var provider = egGridDataProvider.instance({}); $scope.gridDataProvider = provider; - function fetchHolds(offset, count) { - // TODO: LP#1697954 Fetch all holds on grid render to support - // client-side sorting. Migrate to server-side sorting to avoid - // the need for fetching all items. - - // we're going to just fetch all the holds up front - //var ids = patronSvc.hold_ids.slice(offset, offset + count); - return egHolds.fetch_holds(patronSvc.hold_ids).then(null, null, - function(hold_data) { - egCirc.flesh_copy_circ_library(hold_data.copy); - patronSvc.holds.push(hold_data); - return hold_data; - } - ); - } + egCore.org.settings(['circ.holds.canceled.display_count']).then(function(set) { + if (set && set['circ.holds.canceled.display_count']) + $scope.canceled_display_count = set['circ.holds.canceled.display_count']; + }); + egCore.org.settings(['circ.holds.canceled.display_age']).then(function(set) { + if (set && set['circ.holds.canceled.display_age']) + var d = new Date(); + console.log(set['circ.holds.canceled.display_age']); + d.setSeconds(d.getSeconds() - egCore.date.intervalToSeconds(set['circ.holds.canceled.display_age'])); + $scope.canceled_display_age = d.toISOString(); + }); + patronSvc.hold_ids = []; + var hold_count = 0; provider.get = function(offset, count) { // see if we have the requested range cached @@ -72,71 +73,101 @@ function($scope, $q, $routeParams, egCore, egUser, patronSvc, return provider.arrayNotifier(patronSvc.holds, offset, count); } - // see if we have the holds IDs for this range already loaded - if (patronSvc.hold_ids[offset]) { - return fetchHolds(offset, count); + patronSvc.hold_count = 0; + patronSvc.holds = []; + var restrictions = { + usr_id: $scope.patron_id, + fulfillment_time : null + }; + var order_by = []; + var limit; + + if ($scope.holds_display == 'alt') { + restrictions.cancel_time = { + not: null, + greater_than: $scope.canceled_display_age + }; + order_by = [{cancel_time : {not: null}}]; + limit = parseInt($scope.canceled_display_count); + } else { + restrictions.cancel_time = null; + order_by = [ + {pickup_lib: {not: 'current_shelf_lib'}}, + {shelf_time: {not: null}}, + {frozen: {not: null}}, + {request_time: {not : null}}], + limit = null; } - var deferred = $q.defer(); - patronSvc.hold_ids = []; - - var method = 'open-ils.circ.holds.id_list.retrieve.authoritative'; - if ($scope.holds_display == 'alt') - method = 'open-ils.circ.holds.canceled.id_list.retrieve.authoritative'; - - var current = 0; - egCore.net.request( - 'open-ils.circ', method, - egCore.auth.token(), $scope.patron_id - - ).then(function(hold_ids) { - - if (!hold_ids.length || hold_ids.length < offset + 1) - { - deferred.resolve(); - return; + egProgressDialog.open({max : 1, value : 0}); + var first = true; + return egHolds.fetch_wide_holds( + restrictions, + order_by, + limit + ).then(function () { + return provider.arrayNotifier(patronSvc.holds, offset, count); + }, + null, + function(hold_data) { + if (first) { + hold_count = hold_data; + first = false; + egProgressDialog.update({max:patronSvc.hold_count}); + } else { + egProgressDialog.increment(); + var new_item = { id : hold_data.id, hold : hold_data }; + new_item.status_string = + egCore.strings['HOLD_STATUS_' + hold_data.hold_status] + || hold_data.hold_status; + + patronSvc.holds.push(new_item); } + }).finally(egProgressDialog.close); + } - $scope.gridDataProvider.grid.totalCount = hold_ids.length; - - patronSvc.hold_ids = hold_ids; - fetchHolds(offset, count) - .then(deferred.resolve, null, function (data) { - if (data) { - if (current >= offset && current < count) { - deferred.notify(data); - } - current++; - } - }); + function map_prefix_to_subhash (h,pf) { + var newhash = {}; + angular.forEach(Object.keys(h), function(k) { + if (k.startsWith(pf)) { + var nk = k.substr(pf.length); + newhash[nk] = h[k]; + } }); - - return deferred.promise; + return newhash; } $scope.print = function() { - var holds = []; - angular.forEach(patronSvc.holds, function(item) { - holds.push({ - hold : egCore.idl.toHash(item.hold), - copy : egCore.idl.toHash(item.copy), - volume : egCore.idl.toHash(item.volume), - title : item.mvr.title(), - author : item.mvr.author() - }); + var print_holds = []; + angular.forEach(patronSvc.holds, function(hold_data) { + var phold = {}; + print_holds.push(phold); + phold.status_string = hold_data.status_string; + phold.patron_first = hold_data.hold.usr.first_given_name; + phold.patron_last = hold_data.hold.usr_family_name; + phold.patron_alias = hold_data.hold.usr_alias; + phold.patron_barcode = hold_data.hold.ucard_barcode; + + phold.title = hold_data.hold.title; + phold.author = hold_data.hold.author; + + phold.hold = hold_data.hold; + phold.copy = map_prefix_to_subhash(hold_data.hold, 'cp_'); + phold.volume = map_prefix_to_subhash(hold_data.hold, 'cn_'); + phold.part = map_prefix_to_subhash(hold_data.hold, 'p_'); }); egCore.print.print({ context : 'receipt', template : 'holds_for_patron', - scope : {holds : holds} + scope : {holds : print_holds} }); } $scope.detail_view = function(action, user_data, items) { if (h = items[0]) { $location.path('/circ/patron/' + - $scope.patron_id + '/holds/' + h.hold.id()); + $scope.patron_id + '/holds/' + h.hold.id); } } @@ -151,7 +182,7 @@ function($scope, $q, $routeParams, egCore, egUser, patronSvc, // when the detail hold is fetched (and updated), update the bib // record summary display record id. $scope.set_hold = function(hold_data) { - $scope.detail_hold_record_id = hold_data.mvr.doc_id(); + $scope.detail_hold_record_id = hold_data.hold.record_id; } }]) diff --git a/Open-ILS/web/js/ui/default/staff/services/patron_search.js b/Open-ILS/web/js/ui/default/staff/services/patron_search.js index 07e961eefa..5d1bdc0ebf 100644 --- a/Open-ILS/web/js/ui/default/staff/services/patron_search.js +++ b/Open-ILS/web/js/ui/default/staff/services/patron_search.js @@ -38,6 +38,7 @@ function($q , $timeout , $location , egCore, egUser , egConfirmDialog , $locale service.items_out_ids = []; service.holds = []; service.hold_ids = []; + service.hold_count = 0; service.checkout_overrides = {}; service.patron_stats = null; service.noncat_ids = []; -- 2.11.0