%]
[% 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/eframe.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/services/record.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/cat/catalog/app.js"></script>
[% END %]
</div>
<div class="col-md-3">
<div class="btn-group pull-right" dropdown>
- <button type="button" class="btn btn-default dropdown-toggle" ng-disabled="!record_id">
+ <button type="button"
+ class="btn btn-default dropdown-toggle" ng-disabled="!record_id">
[% l('Actions for This Record') %]
<span class="caret"></span>
</button>
<li><a href dropdown-toggle ng-click="set_record_tab('catalog')">[% l('OPAC View') %]</a></li>
<li><a href dropdown-toggle ng-click="set_record_tab('record_html')">[% l('MARC View') %]</a></li>
<li class="divider"></li>
- <li class="disabled"><a href dropdown-toggle>[% l('View Holds') %]</a></li>
+ <li><a href dropdown-toggle ng-click="set_record_tab('holds')">[% l('View Holds') %]</a></li>
<li class="disabled"><a href dropdown-toggle>[% l('Mark as Title Hold Transfer Destination') %]</a></li>
<li class="disabled"><a href dropdown-toggle>[% l('Transfer All Title Holds') %]</a></li>
</ul>
</div>
</div>
-<div class="pad-vert">
+<div>
<!-- ng-show allows the catalog iframe to stay loaded (unlike ng-if) -->
<div ng-show="record_tab == 'catalog'">
<eg-embed-frame url="catalog_url" handlers="handlers" onchange="handle_page"></eg-embed-frame>
<div ng-if="record_tab == 'record_html'">
<eg-record-html record-id="record_id"></eg-record-html>
</div>
+ <div ng-if="record_tab == 'holds'">
+ [% INCLUDE 'staff/cat/catalog/t_holds.tt2' %]
+ </div>
</div>
--- /dev/null
+
+<div ng-if="!detail_hold_id">
+ <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" onchange="pickup_ou_changed"></eg-org-selector>
+ </div>
+ </div>
+ </div>
+ <div class="pad-vert"></div>
+
+ <eg-grid
+ id-field="id"
+ features="-sort,-multisort"
+ items-provider="hold_grid_data_provider"
+ grid-controls="hold_grid_controls"
+ persist-key="cat.catalog.holds">
+
+ <eg-grid-menu-item handler="detail_view"
+ label="[% l('Detail View') %]"></eg-grid-menu-item>
+
+ <eg-grid-action handler="grid_actions.show_recent_circs"
+ label="[% l('Show Last Few Circulations') %]"></eg-grid-action>
+ <eg-grid-action divider="true"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.set_copy_quality"
+ label="[% l('Set Desired Copy Quality') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.edit_pickup_lib"
+ label="[% l('Edit Pickup Library') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.edit_notify_prefs"
+ label="[% l('Edit Notification Settings') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.edit_dates"
+ label="[% l('Edit Hold Dates') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.activate"
+ label="[% l('Activate') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.suspend"
+ label="[% l('Suspend') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.set_top_of_queue"
+ label="[% l('Set Top of Queue') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.clear_top_of_queue"
+ label="[% l('Un-Set Top of Queue') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.transfer_to_marked_title"
+ label="[% l('Transfer To Marked Title') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.mark_damaged"
+ label="[% l('Mark Item Damaged') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.mark_missing"
+ label="[% l('Mark Item Missing') %]"></eg-grid-action>
+ <eg-grid-action divider="true"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.retarget"
+ label="[% l('Find Another Target') %]"></eg-grid-action>
+ <eg-grid-action handler="grid_actions.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>
+
+ <div class="flex-row pad-vert">
+ <div class="flex-cell"></div>
+ <div>
+ <button class="btn btn-default" ng-click="print_holds()">
+ [% l('Print') %]
+ </button>
+ </div>
+ </div>
+</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
+<div>
+ <div>[% l('Holds for record: [_1]', '{{holds[0].title}}') %]</div>
+ <hr/>
+ <style>#holds-for-bib-table td { padding: 5px; }</style>
+ <table id="holds-for-bib-table">
+ <thead>
+ <tr>
+ <th>[% l('Request Date') %]</th>
+ <th>[% l('Patron Barcode') %]</th>
+ <th>[% l('Patron Last') %]</th>
+ <th>[% l('Patron Alias') %]</th>
+ <th>[% l('Current Copy') %]</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="hold in holds">
+ <td>{{hold.hold.request_time | date:'short'}}</td>
+ <td>{{hold.patron_barcode}}</td>
+ <td>{{hold.patron_last}}</td>
+ <td>{{hold.patron_alias}}</td>
+ <td>{{hold.copy.barcode}}</td>
+ </tr>
+ </tbody>
+ </table>
+ <hr/>
+ <div>{{current_location.shortname}} {{today | date:'short'}}</div>
+ <div>[% l('Printed by [_1]', '{{staff.first_given_name}}') %]</div>
+<br/>
+
/**
* TPAC Frame App
+ *
+ * currently, this app doesn't use routes for each sub-ui, because
+ * reloading the catalog each time is sloooow. better so far to
+ * swap out divs w/ ng-if / ng-show / ng-hide as needed.
+ *
*/
-angular.module('egCatalogApp', ['ui.bootstrap','ngRoute','egCoreMod'])
+angular.module('egCatalogApp', ['ui.bootstrap','ngRoute','egCoreMod','egGridMod'])
.config(function($routeProvider, $locationProvider, $compileProvider) {
$locationProvider.html5Mode(true);
resolve : resolver
});
+ // create some catalog page-specific mappings
$routeProvider.when('/cat/catalog/record/:record_id', {
templateUrl: './cat/catalog/t_catalog',
controller: 'CatalogCtrl',
/**
* */
.controller('CatalogCtrl',
- ['$scope','$routeParams','$location','egCore',
-function($scope , $routeParams , $location , egCore) {
+ ['$scope','$routeParams','$location','$q','egCore','egHolds',
+ 'egGridDataProvider','egHoldGridActions',
+function($scope , $routeParams , $location , $q , egCore , egHolds,
+ egGridDataProvider , egHoldGridActions) {
// TODO: is start path configurable in the xul client?
var url = $location.absUrl().replace(/\/staff.*/, '/opac/advanced');
// default to catalog view of the record page
$scope.record_tab = 'catalog';
- $scope.set_record_tab = function(tab) {
- $scope.record_tab = tab;
- }
-
$scope.handle_page = function(url) {
var match = url.match(/\/+opac\/+record\/+(\d+)/);
if (match) {
$scope.record_id = match[1];
- console.debug('loading record ' + $scope.record_id);
// force the record_id to show up in the page.
// not sure why a $digest isn't occuring here.
}
}
+ // xulG handlers
$scope.handlers = {};
+
+ // Holds bits -------------------------------
+ var provider = egGridDataProvider.instance({});
+ $scope.hold_grid_data_provider = provider;
+ $scope.grid_actions = egHoldGridActions;
+ $scope.hold_grid_controls = {};
+
+ var hold_ids = []; // current list of holds
+ function fetchHolds(offset, count) {
+ var ids = hold_ids.slice(offset, offset + count);
+ return egHolds.fetch_holds(ids).then(null, null,
+ function(hold_data) {
+ //patronSvc.holds.push(hold_data);
+ console.log('returning hold ' + hold_data.mvr.title());
+ return hold_data;
+ }
+ );
+ }
+
+ provider.get = function(offset, count) {
+ if ($scope.record_tab != 'holds') return $q.when();
+ var deferred = $q.defer();
+ hold_ids = []; // no caching ATM
+
+ // fetch the IDs
+ egCore.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.holds.retrieve_all_from_title',
+ egCore.auth.token(), $scope.record_id,
+ {pickup_lib : $scope.pickup_ou.id()}
+ ).then(
+ function(hold_data) {
+ angular.forEach(hold_data, function(list, type) {
+ hold_ids = hold_ids.concat(list);
+ });
+ fetchHolds(offset, count).then(
+ deferred.resolve, null, deferred.notify);
+ }
+ );
+
+ return deferred.promise;
+ }
+
+ $scope.detail_view = function(action, user_data, items) {
+ if (h = items[0]) {
+ $scope.detail_hold_id = h.hold.id();
+ }
+ }
+
+ $scope.list_view = function(items) {
+ $scope.detail_hold_id = null;
+ }
+
+ // refresh the list of record holds when the pickup lib is changed.
+ $scope.pickup_ou = egCore.org.get(egCore.auth.user().ws_ou());
+ $scope.pickup_ou_changed = function(org) {
+ $scope.pickup_ou = org;
+ provider.refresh();
+ }
+
+ $scope.set_record_tab = function(tab) {
+ $scope.record_tab = tab;
+
+ if (tab == 'holds') {
+ $scope.detail_hold_record_id = $scope.record_id;
+
+ // refresh the holds grid
+ provider.refresh();
+ }
+ }
+
+ $scope.print_holds = function() {
+ var holds = [];
+ angular.forEach($scope.hold_grid_controls.allItems(), function(item) {
+ holds.push({
+ hold : egCore.idl.toHash(item.hold),
+ patron_last : item.patron_last,
+ patron_alias : item.patron_alias,
+ patron_barcode : item.patron_barcode,
+ copy : egCore.idl.toHash(item.copy),
+ volume : egCore.idl.toHash(item.volume),
+ title : item.mvr.title(),
+ author : item.mvr.author()
+ });
+ });
+
+ egCore.print.print({
+ context : 'receipt',
+ template : 'holds_for_bib',
+ scope : {holds : holds}
+ });
+ }
+
+
}])
// org unit will not be added to the selector.
hiddenTest : '=',
+ // Caller can either $watch(selected, ..) or register an
+ // onchange handler.
+ onchange : '=',
+
// optional primary drop-down button label
label : '@'
},
$scope.orgChanged = function(org) {
$scope.selected = egOrg.get(org.id);
+ if ($scope.onchange) $scope.onchange($scope.selected);
}
if (!$scope.selected)