--- /dev/null
+[%
+ WRAPPER "staff/base.tt2";
+ ctx.page_title = l("Holds Shelf");
+ ctx.page_app = "egHoldsApp";
+%]
+
+[% BLOCK APP_JS %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/circ.js"></script>
+[% INCLUDE 'staff/circ/share/circ_strings.tt2' %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/holds.js"></script>
+[% INCLUDE 'staff/circ/share/hold_strings.tt2' %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/holds/app.js"></script>
+<link rel="stylesheet" href="[% ctx.base_path %]/staff/css/circ.css" />
+[% END %]
+
+<div ng-view></div>
+
+[% END %]
--- /dev/null
+<div class="row">
+ <div class="col-md-3">
+ <div class="input-group">
+ <span class="input-group-addon">[% l('Pickup Library') %]</span>
+ <eg-org-selector selected="pickup_ou"></eg-org-selector>
+ </div>
+ </div>
+ <div class="col-md-2">
+ <div class="checkbox">
+ <label>
+ <input ng-model="show_cleared" type="checkbox"/>
+ [% l('View Clearable Holds') %]
+ </label>
+ </div>
+ </div>
+</div>
+<div class="pad-vert"></div>
+
+<div ng-if="!detail_hold_id">
+[% INCLUDE 'staff/circ/holds/t_shelf_list.tt2' %]
+</div>
+
+<!-- hold details -->
+<div ng-if="detail_hold_id">
+ <div class="row">
+ <div class="col-md-2">
+ <button class="btn btn-default" ng-click="list_view()">
+ [% l('List View') %]
+ </button>
+ </div>
+ </div>
+ <div class="pad-vert"></div>
+ <eg-record-summary record='detail_hold_record'
+ record-id="detail_hold_record_id"></eg-record-summary>
+ <eg-hold-details hold-retrieved="set_hold" hold-id="detail_hold_id"></eg-hold-details>
+</div>
--- /dev/null
+
+<eg-grid
+ id-field="id"
+ features="-sort,-multisort"
+ items-provider="gridDataProvider"
+ persist-key="circ.holds.shelf">
+
+ <eg-grid-menu-item handler="detail_view"
+ label="[% l('Detail View') %]"></eg-grid-menu-item>
+
+ <eg-grid-action handler="show_recent_circs"
+ label="[% l('Show Last Few Circulations') %]"></eg-grid-action>
+ <eg-grid-action divider="true"></eg-grid-action>
+ <eg-grid-action handler="set_copy_quality"
+ label="[% l('Set Desired Copy Quality') %]"></eg-grid-action>
+ <eg-grid-action handler="edit_pickup_lib"
+ label="[% l('Edit Pickup Library') %]"></eg-grid-action>
+ <eg-grid-action handler="edit_notify_prefs"
+ label="[% l('Edit Notification Settings') %]"></eg-grid-action>
+ <eg-grid-action handler="edit_dates"
+ label="[% l('Edit Hold Dates') %]"></eg-grid-action>
+ <eg-grid-action handler="activate"
+ label="[% l('Activate') %]"></eg-grid-action>
+ <eg-grid-action handler="suspend"
+ label="[% l('Suspend') %]"></eg-grid-action>
+ <eg-grid-action handler="set_top_of_queue"
+ label="[% l('Set Top of Queue') %]"></eg-grid-action>
+ <eg-grid-action handler="clear_top_of_queue"
+ label="[% l('Un-Set Top of Queue') %]"></eg-grid-action>
+ <eg-grid-action handler="transfer_to_marked_title"
+ label="[% l('Transfer To Marked Title') %]"></eg-grid-action>
+ <eg-grid-action handler="mark_damaged"
+ label="[% l('Mark Item Damaged') %]"></eg-grid-action>
+ <eg-grid-action handler="mark_missing"
+ label="[% l('Mark Item Missing') %]"></eg-grid-action>
+ <eg-grid-action divider="true"></eg-grid-action>
+ <eg-grid-action handler="retarget"
+ label="[% l('Find Another Target') %]"></eg-grid-action>
+ <eg-grid-action handler="cancel_hold"
+ label="[% l('Cancel Hold') %]"></eg-grid-action>
+
+ <eg-grid-field label="[% l('Hold ID') %]" path='hold.id'></eg-grid-field>
+ <eg-grid-field label="[% l('Current Copy') %]"
+ path='hold.current_copy.barcode'>
+ <a href="./cat/item/{{item.hold.current_copy().id()}}/summary" target="_self">
+ {{item.hold.current_copy().barcode()}}
+ </a>
+ </eg-grid-field>
+
+ <eg-grid-field label="[% l('Request Date') %]" path='hold.request_time'></eg-grid-field>
+ <eg-grid-field label="[% l('Capture Date') %]" path='hold.capture_time'></eg-grid-field>
+ <eg-grid-field label="[% l('Available Date') %]" path='hold.shelf_time'></eg-grid-field>
+ <eg-grid-field label="[% l('Hold Type') %]" path='hold.hold_type'></eg-grid-field>
+ <eg-grid-field label="[% l('Pickup Library') %]" path='hold.pickup_lib.shortname'></eg-grid-field>
+
+ <eg-grid-field label="[% l('Title') %]" path='mvr.title'>
+ <a href="[% ctx.base_path %]/opac/record/{{item.mvr.doc_id()}}">
+ {{item.mvr.title()}}
+ </a>
+ </eg-grid-field>
+
+ <eg-grid-field label="[% l('Author') %]" path='mvr.author'></eg-grid-field>
+ <eg-grid-field label="[% l('Potential Copies') %]" path='potential_copies'></eg-grid-field>
+ <eg-grid-field label="[% l('Status') %]" path='status_string'></eg-grid-field>
+
+ <eg-grid-field label="[% l('Queue Position') %]" path='queue_position' hidden></eg-grid-field>
+ <eg-grid-field path='hold.*' parent-idl-class="ahr" hidden></eg-grid-field>
+ <eg-grid-field path='copy.*' parent-idl-class="acp" hidden></eg-grid-field>
+ <eg-grid-field path='volume.*' parent-idl-class="acn" hidden></eg-grid-field>
+ <eg-grid-field path='mvr.*' parent-idl-class="mvr" hidden></eg-grid-field>
+</eg-grid>
+
<span>[% l('Record In-House Use') %]</span>
</a>
</li>
+ <li>
+ <a href="./circ/holds/shelf" target="_self">
+ <span class="glyphicon glyphicon-tasks"></span>
+ <span>[% l('View Holds Shelf') %]</span>
+ </a>
+ </li>
<li class="divider"></li>
<li>
<a href="./cat/item/replace_barcode/index" target="_self">
--- /dev/null
+angular.module('egHoldsApp',
+ ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod', 'egGridMod'])
+
+.config(function($routeProvider, $locationProvider, $compileProvider) {
+ $locationProvider.html5Mode(true);
+ $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); // grid export
+
+ var resolver = {delay :
+ ['egStartup', function(egStartup) {return egStartup.go()}]}
+
+ $routeProvider.when('/circ/holds/shelf', {
+ templateUrl: './circ/holds/t_shelf',
+ controller: 'HoldsShelfCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.when('/circ/holds/shelf/:hold_id', {
+ templateUrl: './circ/holds/t_shelf',
+ controller: 'HoldsShelfCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.otherwise({redirectTo : '/circ/holds/shelf'});
+})
+
+.controller('HoldsShelfCtrl',
+ ['$scope','$q','$routeParams','$window','$location','egCore','egHolds','egCirc','egGridDataProvider',
+function($scope , $q , $routeParams , $window , $location , egCore , egHolds , egCirc , egGridDataProvider) {
+ $scope.detail_hold_id = $routeParams.hold_id;
+
+ var hold_ids = [];
+ var holds = [];
+
+ function fetch_holds(offset, count) {
+ var ids = hold_ids.slice(offset, offset + count);
+ return egHolds.fetch_holds(ids).then(null, null,
+ function(hold_data) {
+ holds.push(hold_data);
+ return hold_data; // to the grid
+ }
+ );
+ }
+
+ var provider = egGridDataProvider.instance({});
+ $scope.gridDataProvider = provider;
+
+ provider.get = function(offset, count) {
+
+ // see if we have the requested range cached
+ if (holds[offset]) {
+ return provider.arrayNotifier(patronSvc.holds, offset, count);
+ }
+
+ // see if we have the holds IDs for this range already loaded
+ if (hold_ids[offset]) {
+ return fetch_holds(offset, count);
+ }
+
+ var deferred = $q.defer();
+ hold_ids = [];
+ holds = [];
+
+ var method = 'open-ils.circ.captured_holds.id_list.on_shelf.retrieve.authoritative.atomic';
+ /*
+ if ($scope.holds_display == 'alt')
+ method = 'open-ils.circ.holds.canceled.id_list.retrieve.authoritative';
+ */
+
+ egCore.net.request(
+ 'open-ils.circ', method,
+ egCore.auth.token(), $scope.pickup_ou.id()
+
+ ).then(function(ids) {
+ if (!ids.length) {
+ deferred.resolve();
+ return;
+ }
+
+ hold_ids = ids;
+ fetch_holds(offset, count)
+ .then(deferred.resolve, null, deferred.notify);
+ });
+
+ return deferred.promise;
+ }
+
+ function refresh_page() {
+ holds = [];
+ hold_ids = [];
+ provider.refresh();
+ }
+
+
+ // re-draw the grid when user changes the org selector
+ $scope.pickup_ou = egCore.org.get(egCore.auth.user().ws_ou());
+ $scope.$watch('pickup_ou', function(newVal, oldVal) {
+ if (newVal && newVal != oldVal)
+ refresh_page();
+ });
+
+ $scope.detail_view = function(action, user_data, items) {
+ if (h = items[0]) {
+ $location.path('/circ/holds/shelf/' + h.hold.id());
+ }
+ }
+
+ $scope.list_view = function(items) {
+ $location.path('/circ/holds/shelf');
+ }
+
+ // 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();
+ }
+
+ refresh_page();
+
+}]);
+
$scope.gridDataProvider = provider;
function fetchHolds(offset, count) {
-
var ids = patronSvc.hold_ids.slice(offset, offset + count);
-
- return egCore.net.request(
- 'open-ils.circ',
- 'open-ils.circ.hold.details.batch.retrieve.authoritative',
- egCore.auth.token(), ids
-
- ).then(null, null, function(hold_data) {
- $scope.loading = false;
-
- var hold = hold_data.hold;
- hold_data.id = hold.id();
- egHolds.local_flesh(hold_data);
-
- patronSvc.holds.push(hold_data);
- return hold_data;
- });
+ return egHolds.fetch_holds(ids).then(
+ function() { $scope.loading = false; },
+ null,
+ function(hold_data) { patronSvc.holds.push(hold_data) }
+ );
}
provider.get = function(offset, count) {
var service = {};
+ service.fetch_holds = function(hold_ids) {
+
+ return egCore.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.hold.details.batch.retrieve.authoritative',
+ egCore.auth.token(), hold_ids
+
+ ).then(null, null, function(hold_data) {
+ var hold = hold_data.hold;
+ hold_data.id = hold.id();
+ service.local_flesh(hold_data);
+ return hold_data;
+ });
+ }
+
+
service.cancel_holds = function(hold_ids) {
return $modal.open({
// user's expectations. Note this allows us to retain
// the timezone.
function strip_time(date) {
- if (!date) return null;
+ if (!date) date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);