[% 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/services/record.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/app.js"></script>
<!-- load the rest on demand? -->
<!-- patron holds list -->
<ul class="nav nav-tabs">
- <li ng-class="{active : holds_display == 'main'}">
+ <li ng-class="{active : holds_display == 'main', disabled : detail_hold_id}">
<a href ng-click="show_main_list()">[% l('Open Hold Requests') %]</a>
</li>
- <li ng-class="{active : holds_display == 'alt'}">
+ <li ng-class="{active : holds_display == 'alt', disabled : detail_hold_id}">
<a href ng-click="show_alt_list()">[% l('Recently Canceled Holds') %]</a>
</li>
</ul>
<div class="pad-vert"></div>
-<eg-grid
- id-field="id"
- features="-sort,-multisort"
- items-provider="gridDataProvider"
- persist-key="circ.patron.holds">
-
- <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>
-
-<div class="flex-row pad-vert">
- <div class="flex-cell"></div>
- <div><button class="btn btn-default" ng-click="print()">
- [% l('Print') %]
- </button>
+<div ng-if="!detail_hold_id">
+[% INCLUDE 'staff/circ/patron/t_holds_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.patron.holds">
+
+ <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>
+
+<div class="flex-row pad-vert">
+ <div class="flex-cell"></div>
+ <div>
+ <button class="btn btn-default" ng-click="print()">
+ [% l('Print') %]
+ </button>
+ </div>
+</div>
+
<script>
angular.module('egCoreMod').run(['egStrings', function(s) {
+s['HOLD_STATUS_-1'] = "[% l('Error (-1)') %]";
s.HOLD_STATUS_1 = "[% l('Waiting for Copy') %]";
s.HOLD_STATUS_2 = "[% l('Waiting for Capture') %]";
s.HOLD_STATUS_3 = "[% l('In Transit') %]";
--- /dev/null
+<!-- hold info -->
+<h4 class="pad-vert">[% l('Hold Details') %]</h4>
+<div class="flex-row">
+ <div class="flex-cell">[% l('Request Date') %]</div>
+ <div class="flex-cell well">{{hold.request_time() | date:'short'}}</div>
+ <div class="flex-cell">[% l('Capture Date') %]</div>
+ <div class="flex-cell well">{{hold.capture_time() | date:'short'}}</div>
+ <div class="flex-cell">[% l('Available On') %]</div>
+ <div class="flex-cell well">{{hold.shelf_time() | date:'short'}}</div>
+ </div>
+<div class="flex-row">
+ <div class="flex-cell">[% l('Hold Type') %]</div>
+ <div class="flex-cell well">{{hold.hold_type()}}</div>
+ <div class="flex-cell">[% l('Current Copy') %]</div>
+ <div class="flex-cell well">
+ <a href="./cat/item/{{hold.current_copy().id()}}" target="_self">
+ {{hold.current_copy().barcode()}}
+ </a>
+ </div>
+ <div class="flex-cell">[% l('Call Number') %]</div>
+ <div class="flex-cell well">{{volume.label()}}</div>
+</div>
+<div class="flex-row">
+ <div class="flex-cell">[% l('Pickup Lib') %]</div>
+ <div class="flex-cell well">{{hold.pickup_lib().shortname()}}</div>
+ <div class="flex-cell">[% l('Status') %]</div>
+ <div class="flex-cell well">{{status_string}}</div>
+ <div class="flex-cell">[% l('Behind Desk') %]</div>
+ <div class="flex-cell well">{{hold.behind_desk() == 't'}}</div>
+</div>
+<div class="flex-row">
+ <div class="flex-cell">[% l('Current Shelf Lib') %]</div>
+ <div class="flex-cell well">{{hold.current_shelf_lib().shortname()}}</div>
+ <div class="flex-cell">[% l('Current Copy Location') %]</div>
+ <div class="flex-cell well">{{copy.location().name()}}</div>
+ <div class="flex-cell">[% l('Force Copy Quality') %]</div>
+ <div class="flex-cell well">{{hold.mint_condition() == 't'}}</div>
+</div>
+<div class="flex-row">
+ <div class="flex-cell">[% l('Email Notify') %]</div>
+ <div class="flex-cell well">{{hold.email_notify() == 't'}}</div>
+ <div class="flex-cell">[% l('Phone Notify') %]</div>
+ <div class="flex-cell well">{{hold.phone_notify()}}</div>
+ <div class="flex-cell">[% l('SMS Notify') %]</div>
+ <div class="flex-cell well">{{hold.sms_notify()}}</div>
+</div>
+<div class="flex-row">
+ <div class="flex-cell">[% l('Cancel Cause') %]</div>
+ <div class="flex-cell well">{{hold.cancel_cause().label()}}</div>
+ <div class="flex-cell">[% l('Cancel Time') %]</div>
+ <div class="flex-cell well">{{hold.cancel_time() | date:'short'}}</div>
+ <div class="flex-cell">[% l('Cancel Note') %]</div>
+ <div class="flex-cell well">{{hold.cancel_note()}}</div>
+</div>
+
+<ul class="nav nav-tabs pad-vert" ng-init="detail_tab='notes'">
+ <li ng-class="{active : detail_tab == 'notes'}">
+ <a href ng-click="detail_tab = 'notes'">[% l('Notes') %]</a>
+ </li>
+ <li ng-class="{active : detail_tab == 'notify'}">
+ <a href ng-click="detail_tab = 'notify'">
+ [% l('Manual Notifications') %]
+ </a>
+ </li>
+</ul>
+<div class="tab-content">
+ <div class="tab-pane active">
+
+ <div ng-if="detail_tab == 'notes'">
+
+ <button class="btn btn-default" ng-click="new_note()">
+ [% l('New Note') %]
+ </button>
+
+ <div class="row pad-vert" ng-repeat="note in hold.notes()">
+ <div class="col-md-12">
+ <div class="row">
+ <div class="col-md-6 strong-text">{{note.title()}}</div>
+ <div class="col-md-6">
+ <div class="pull-right">
+ <span class="pad-horiz alert alert-info"
+ ng-if="note.slip() == 't'">[% l('Print on Slip') %]</span>
+ <span class="pad-horiz alert alert-warning"
+ ng-if="note.pub() == 't'">[% l('Patron Visible') %]</span>
+ <span class="pad-horiz alert alert-info"
+ ng-if="note.pub() == 'f'">[% l('Staff Only') %]</span>
+ <span class="pad-horiz alert alert-info"
+ ng-if="note.staff() == 't'">[% l('Staff Created') %]</span>
+ <span class="pad-horiz alert alert-info"
+ ng-if="note.staff() == 'f'">[% l('Patron Created') %]</span>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <!-- hmm, not sure why the margin-left is needed.. the well? -->
+ <div class="col-md-12 well" style="margin-left:12px">
+ <div class="row">
+ <div class="col-md-8">
+ <div class="">{{note.body()}}</div>
+ </div>
+ <div class="col-md-4">
+ <div class="pull-right">
+ <button ng-click="delete_note(note)" class="btn btn-warning">
+ [% l('Delete') %]
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div><!-- notes tab content -->
+
+ </div><!-- tab pane -->
+</div><!-- tab-content -->
+
}
})
+/*
+ * A record='foo' attribute is required as a storage location of the
+ * retrieved record
+ */
.directive('egRecordSummary', function() {
return {
restrict : 'AE',
recordId : '=',
record : '='
},
- templateUrl : '/eg/staff/cat/share/t_record_summary', // FIXME: ABS URL
+ templateUrl : './cat/share/t_record_summary',
controller :
['$scope','egCore',
function($scope , egCore) {
egCore.pcrud.retrieve('bre', $scope.recordId, {
flesh : 1,
flesh_fields : {
- bre : ['simple_record']
+ bre : ['simple_record','creator','editor']
}
}).then(function(rec) {
+ rec.owner(egCore.org.get(rec.owner()));
$scope.record = rec;
});
}
resolve : resolver
});
+ $routeProvider.when('/circ/patron/:id/holds/:hold_id', {
+ templateUrl: './circ/patron/t_holds',
+ controller: 'PatronHoldsCtrl',
+ resolve : resolver
+ });
+
+ $routeProvider.when('/circ/patron/:id/hold/:hold_id', {
+ templateUrl: './circ/patron/t_hold_details',
+ controller: 'PatronHoldDetailsCtrl',
+ resolve : resolver
+ });
+
$routeProvider.when('/circ/patron/:id/bills', {
templateUrl: './circ/patron/t_bills',
controller: 'PatronBillsCtrl',
$scope.initTab('holds', $routeParams.id);
$scope.holds_display = 'main';
+ $scope.detail_hold_id = $routeParams.hold_id;
function refresh_all() {
patronSvc.refreshPrimary();
).then(null, null, function(hold_data) {
$scope.loading = false;
- hold_data.status_string =
- egCore.strings['HOLD_STATUS_' + hold_data.status]
- || hold_data.status;
-
var hold = hold_data.hold;
hold_data.id = hold.id();
- hold.pickup_lib(egCore.org.get(hold.pickup_lib())); // flesh
-
- // current_copy is only sometimes fleshed. Not sure whye.
- if (hold.current_copy() && typeof hold.current_copy() != 'object')
- hold.current_copy(hold_data.copy);
+ egHolds.local_flesh(hold_data);
patronSvc.holds.push(hold_data);
return hold_data;
});
}
-}])
+ $scope.detail_view = function(action, user_data, items) {
+ if (h = items[0]) {
+ $location.path('/circ/patron/' +
+ $scope.patron_id + '/holds/' + h.hold.id());
+ }
+ }
+ $scope.list_view = function(items) {
+ $location.path('/circ/patron/' + $scope.patron_id + '/holds');
+ }
+
+ // 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();
+ }
+}])
return deferred.promise;
}
+ // fleshes orgs, etc. for hold data blobs retrieved from
+ // open-ils.circ.hold.details[.batch].retrieve
+ service.local_flesh = function(hold_data) {
+
+ hold_data.status_string =
+ egCore.strings['HOLD_STATUS_' + hold_data.status]
+ || hold_data.status;
+
+ var hold = hold_data.hold;
+ hold.pickup_lib(egCore.org.get(hold.pickup_lib()));
+ hold.current_shelf_lib(egCore.org.get(hold.current_shelf_lib()));
+
+ // current_copy is not always fleshed in the API
+ if (hold.current_copy() && typeof hold.current_copy() != 'object')
+ hold.current_copy(hold_data.copy);
+ }
+
return service;
}])
+/**
+ * Hold details interface
+ */
+.directive('egHoldDetails', function() {
+ return {
+ restrict : 'AE',
+ templateUrl : './circ/share/t_hold_details',
+ scope : {
+ holdId : '=',
+ // if set, called whenever hold details are retrieved. The
+ // argument is the hold blob returned from hold.details.retrieve
+ holdRetrieved : '=',
+ showPatron : '='
+ },
+ controller : [
+ '$scope','egCore','egHolds','egCirc',
+ function($scope , egCore , egHolds , egCirc) {
+
+ function draw() {
+ if (!$scope.holdId) return;
+
+ egCore.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.hold.details.retrieve.authoritative',
+ egCore.auth.token(), $scope.holdId
+
+ ).then(function(hold_data) {
+ egHolds.local_flesh(hold_data);
+
+ angular.forEach(hold_data,
+ function(val, key) { $scope[key] = val });
+
+ // fetch + flesh the cancel_cause if needed
+ if ($scope.hold.cancel_time()) {
+ egHolds.get_cancel_reasons().then(function() {
+ // egHolds caches the causes in egEnv
+ $scope.hold.cancel_cause(
+ egCore.env.ahrcc.map[$scope.hold.cancel_cause()]);
+ })
+ }
+
+ if ($scope.hold.current_copy()) {
+ egCirc.flesh_copy_location($scope.hold.current_copy());
+ }
+
+ if ($scope.holdRetrieved)
+ $scope.holdRetrieved(hold_data);
+
+ });
+ }
+
+ $scope.delete_note = function(note) {
+ egCore.pcrud.remove(note).then(function() {
+ // remove the deleted note from the locally fleshed notes
+ $scope.hold.notes(
+ $scope.hold.notes().filter(function(n) {
+ return n.id() != note.id()
+ })
+ );
+ });
+ }
+
+ /*
+ $scope.new_note = function() {
+ $modal.open({
+ templateUrl : './circ/patron
+ }
+ */
+
+ $scope.$watch('holdId', function(newVal, oldVal) {
+ if (newVal != oldVal) draw();
+ });
+
+ draw();
+ }
+ ]
+ }
+})
+