<field reporter:label="Shelf Expire Time" name="shelf_expire_time" reporter:datatype="timestamp"/>
<field reporter:label="Notes" name="notes" reporter:datatype="link" oils_persist:virtual="true"/>
<field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
+ <field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
<field reporter:label="Issuance Label" name="issuance_label" reporter:datatype="text" />
<field reporter:label="Is Staff Hold?" name="is_staff_hold" reporter:datatype="bool" />
<field reporter:label="Potential Copies" name="potential_copies" reporter:datatype="int" />
+ <field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
<field reporter:label="Shelf Expire Time" name="shelf_expire_time" reporter:datatype="timestamp"/>
<field reporter:label="Notes" name="notes" reporter:datatype="link" oils_persist:virtual="true"/>
<field reporter:label="Current Shelf Lib" name="current_shelf_lib" reporter:datatype="org_unit"/>
+ <field reporter:label="Behind Desk" name="behind_desk" reporter:datatype="bool"/>
</fields>
<links>
<link field="fulfillment_lib" reltype="has_a" key="id" map="" class="aou"/>
$hold->target( $li->eg_bib_id );
}
+ # if behind-the-desk holds are supported at the
+ # pickup library, apply the patron default
+ my $bdous = $U->ou_ancestor_setting_value(
+ $hold->pickup_lib,
+ 'circ.holds.behind_desk_pickup_supported',
+ $mgr->editor
+ );
+
+ if ($bdous) {
+ my $set = $mgr->editor->search_actor_user_setting(
+ {usr => $hold->usr, name => 'circ.holds_behind_desk'})->[0];
+
+ $hold->behind_desk('t') if $set and
+ OpenSRF::Utils::JSON->JSON2perl($set->value);
+ }
+
$mgr->editor->create_action_hold_request( $hold ) or return 0;
}
api_name => "open-ils.actor.user.hold_requests.count",
authoritative => 1,
argc => 1,
- notes => 'Returns hold ready/total counts'
+ notes => q/
+ Returns hold ready vs. total counts.
+ If a context org unit is provided, a third value
+ is returned with key 'behind_desk', which reports
+ how many holds are ready at the pickup library
+ with the behind_desk flag set to true.
+ /
);
sub hold_request_count {
- my( $self, $client, $authtoken, $user_id ) = @_;
+ my( $self, $client, $authtoken, $user_id, $ctx_org ) = @_;
my $e = new_editor(authtoken => $authtoken);
return $e->event unless $e->checkauth;
}
my $holds = $e->json_query({
- select => {ahr => ['pickup_lib', 'current_shelf_lib']},
+ select => {ahr => ['pickup_lib', 'current_shelf_lib', 'behind_desk']},
from => 'ahr',
where => {
usr => $user_id,
}
});
- return {
+ my @ready = grep {
+ $_->{current_shelf_lib} and # avoid undef warnings
+ $_->{pickup_lib} eq $_->{current_shelf_lib}
+ } @$holds;
+
+ my $resp = {
total => scalar(@$holds),
- ready => scalar(
- grep {
- $_->{current_shelf_lib} and # avoid undef warnings
- $_->{pickup_lib} eq $_->{current_shelf_lib}
- } @$holds
- )
+ ready => scalar(@ready)
};
+
+ if ($ctx_org) {
+ # count of holds ready at pickup lib with behind_desk true.
+ $resp->{behind_desk} = scalar(
+ grep {
+ $_->{pickup_lib} == $ctx_org and
+ $U->is_true($_->{behind_desk})
+ } @ready
+ );
+ }
+
+ return $resp;
}
__PACKAGE__->register_method(
use OpenSRF::Utils qw/:datetime/;
use Digest::MD5 qw(md5_hex);
use OpenSRF::Utils::Cache;
+use OpenSRF::Utils::JSON;
my $apputils = "OpenILS::Application::AppUtils";
my $U = $apputils;
$hold->expire_time(calculate_expire_time($recipient->home_ou));
}
+
+ # if behind-the-desk pickup is supported at the hold pickup lib,
+ # set the value to the patron default, unless a value has already
+ # been applied. If it's not supported, force the value to false.
+
+ my $bdous = $U->ou_ancestor_setting_value(
+ $hold->pickup_lib,
+ 'circ.holds.behind_desk_pickup_supported', $e);
+
+ if ($bdous) {
+ if (!defined $hold->behind_desk) {
+
+ my $set = $e->search_actor_user_setting({
+ usr => $hold->usr,
+ name => 'circ.holds_behind_desk'
+ })->[0];
+
+ $hold->behind_desk('t') if $set and
+ OpenSRF::Utils::JSON->JSON2perl($set->value);
+ }
+ } else {
+ # behind the desk not supported, force it to false
+ $hold->behind_desk('f');
+ }
+
$hold->requestor($e->requestor->id);
$hold->request_lib($e->requestor->ws_ou);
$hold->selection_ou($hold->pickup_lib) unless $hold->selection_ou;
my $stat = $self->_load_user_with_prefs;
return $stat if $stat;
+ # if behind-desk holds are supported and the user
+ # setting which controls the value is opac-visible,
+ # add the setting to the list of settings to manage.
+ # note: this logic may need to be changed later to
+ # check whether behind-the-desk holds are supported
+ # anywhere the patron may select as a pickup lib.
+ my $e = $self->editor;
+ my $bdous = $self->ctx->{get_org_setting}->(
+ $e->requestor->home_ou,
+ 'circ.holds.behind_desk_pickup_supported');
+
+ if ($bdous) {
+ my $setting =
+ $e->retrieve_config_usr_setting_type(
+ 'circ.holds_behind_desk');
+
+ if ($U->is_true($setting->opac_visible)) {
+ push(@user_prefs, 'circ.holds_behind_desk');
+ $self->ctx->{behind_desk_supported} = 1;
+ }
+ }
+
return Apache2::Const::OK
unless $self->cgi->request_method eq 'POST';
cut_in_line BOOL,
mint_condition BOOL NOT NULL DEFAULT TRUE,
shelf_expire_time TIMESTAMPTZ,
- current_shelf_lib INT REFERENCES actor.org_unit DEFERRABLE INITIALLY DEFERRED
+ current_shelf_lib INT REFERENCES actor.org_unit DEFERRABLE INITIALLY DEFERRED,
+ behind_desk BOOLEAN NOT NULL DEFAULT FALSE
);
ALTER TABLE action.hold_request ADD CONSTRAINT sms_check CHECK (
sms_notify IS NULL
--- /dev/null
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+ALTER TABLE action.hold_request
+ ADD COLUMN behind_desk BOOLEAN NOT NULL DEFAULT FALSE;
+
+-- The value on the hold is the new arbiter of whether a
+-- hold should be held behind the desk and reported as such
+-- Update existing holds that would in the current regime
+-- be considered behind-the-desk holds to use the new column
+
+UPDATE action.hold_request ahr
+ SET behind_desk = TRUE
+ FROM actor.usr_setting aus
+ WHERE
+ ahr.cancel_time IS NULL AND
+ ahr.fulfillment_time IS NULL AND
+ aus.usr = ahr.usr AND
+ aus.name = 'circ.holds_behind_desk' AND
+ aus.value = 'true' AND
+ EXISTS (
+ SELECT 1
+ FROM actor.org_unit_ancestor_setting(
+ 'circ.holds.behind_desk_pickup_supported',
+ ahr.pickup_lib
+ )
+ WHERE value = 'true'
+ );
+
+COMMIT;
[% IF ctx.user_setting_map.$setting %] checked='checked' [% END %]/>
</td>
</tr>
+ [%- setting = 'circ.holds_behind_desk'; IF ctx.behind_desk_supported -%]
+ <tr>
+ <td><label for='[% setting %]'>[% l('Pickup holds from behind the desk when possible?') %]</label></td>
+ <td>
+ <input id='[% setting %]' name='[% setting %]' type="checkbox"
+ [% IF ctx.user_setting_map.$setting %] checked='checked' [% END %]/>
+ </td>
+ </tr>
+ [% END %]
+
<!--
<tr>
<td><label for='prefs_def_font'>[% l("Default Font Size") %]</label></td>
<!ENTITY staff.patron_display.first_given_name.label 'First Name:'>
<!ENTITY staff.patron_display.holds.label 'Holds:'>
<!ENTITY staff.patron_display.holds_available.label 'Available:'>
+<!ENTITY staff.patron_display.holds_available_behind_desk.label 'Behind Desk:'>
<!ENTITY staff.patron_display.home_ou.label 'Home Library:'>
<!ENTITY staff.patron_display.ident1.label 'ID 1:'>
<!ENTITY staff.patron_display.ident2.label 'ID 2:'>
return document.getElementById('circStrings').getString('staff.circ.utils.no');
}
}
+ },
+ {
+ 'persist' : 'hidden width ordinal',
+ 'id' : 'behind_desk',
+ 'label' : document.getElementById('circStrings').getString('staff.circ.utils.hold.behind_desk'),
+ 'flex' : 1,
+ 'primary' : false,
+ 'hidden' : true,
+ 'editable' : false,
+ 'render' : function(my) {
+ if (isTrue(my.ahr.behind_desk())) {
+ return document.getElementById('circStrings').getString('staff.circ.utils.yes');
+ } else {
+ return document.getElementById('circStrings').getString('staff.circ.utils.no');
+ }
+ }
}
+
];
for (var i = 0; i < c.length; i++) {
if (modify[ c[i].id ]) {
} else {
print_data.route_to_msg = document.getElementById('circStrings').getFormattedString('staff.circ.utils.route_to.msg', [check.route_to]);
print_data.route_to = check.route_to;
- var behind_the_desk_support = String( data.hash.aous['circ.holds.behind_desk_pickup_supported'] ) == 'true';
- if (behind_the_desk_support) {
- var usr_settings = network.simple_request('FM_AUS_RETRIEVE',[ses(),check.payload.hold.usr()]);
- if (typeof usr_settings['circ.holds_behind_desk'] != 'undefined') {
- if (usr_settings['circ.holds_behind_desk']) {
- print_data.prefer_behind_holds_desk = true;
- check.route_to = document.getElementById('circStrings').getString('staff.circ.route_to.private_hold_shelf');
- print_data.route_to_msg = document.getElementById('circStrings').getFormattedString('staff.circ.utils.route_to.msg', [check.route_to]);
- print_data.route_to = check.route_to;
- } else {
- check.route_to = document.getElementById('circStrings').getString('staff.circ.route_to.public_hold_shelf');
- print_data.route_to_msg = document.getElementById('circStrings').getFormattedString('staff.circ.utils.route_to.msg', [check.route_to]);
- print_data.route_to = check.route_to;
- }
- } else {
- check.route_to = document.getElementById('circStrings').getString('staff.circ.route_to.public_hold_shelf');
- print_data.route_to_msg = document.getElementById('circStrings').getFormattedString('staff.circ.utils.route_to.msg', [check.route_to]);
- print_data.route_to = check.route_to;
- }
+
+ // If the hold is marked as behind-shelf, report it as such
+ // in the receipt, regardless of any org or user settings.
+ if (isTrue(check.payload.hold.behind_desk())) {
+ print_data.prefer_behind_holds_desk = true;
+ check.route_to = document.getElementById('circStrings').getString('staff.circ.route_to.private_hold_shelf');
+ print_data.route_to_msg = document.getElementById('circStrings').getFormattedString('staff.circ.utils.route_to.msg', [check.route_to]);
+ print_data.route_to = check.route_to;
+ } else {
+ check.route_to = document.getElementById('circStrings').getString('staff.circ.route_to.public_hold_shelf');
+ print_data.route_to_msg = document.getElementById('circStrings').getFormattedString('staff.circ.utils.route_to.msg', [check.route_to]);
+ print_data.route_to = check.route_to;
}
+
print_data.destination_shelf_msg = print_data.route_to_msg;
print_data.destination_shelf = print_data.route_to;
msg += print_data.route_to_msg;
staff.circ.utils.capture_time=Capture Date
# Date the hold was cancelled
staff.circ.utils.hold_cancel_time=Cancel Time
+staff.circ.utils.hold.behind_desk=Behind Desk
# Controlled entry for why the hold was cancelled
staff.circ.utils.hold_cancel_cause=Cancel Cause
# Freetext note pertaining to the cancelled hold
staff.item.batch.hold.override_btn_label=Override
staff.item.batch.hold.user_not_found=User Not Found
+# hold count tooltip labels
+staff.patron.summary.hold_counts_behind_desk=Available / Total (Behind Desk)
+staff.patron.summary.hold_counts=Available / Total
+
return function() {
util.widgets.set_text(e,'...');
var e2 = document.getElementById('patron_holds_available');
+ var e3 = document.getElementById('patron_holds_available_behind_desk');
if (e2) util.widgets.set_text(e2,'...');
+ if (e3) util.widgets.set_text(e3,'...');
var under_btn;
if (xulG) {
if (xulG.display_window) {
}
obj.network.simple_request(
'FM_AHR_COUNT_RETRIEVE.authoritative',
- [ ses(), obj.patron.id() ],
+ [ ses(), obj.patron.id(), ses('ws_ou') ],
function(req) {
var robj = req.getResultObject();
util.widgets.set_text(e,
robj.total
);
- if (e2) util.widgets.set_text(e2,
- robj.ready
- );
- if (under_btn) util.widgets.set_text(under_btn, req.getResultObject().ready + '/' + req.getResultObject().total );
+ if (e2) {
+ util.widgets.set_text(e2, robj.ready);
+ }
+ if (e3) {
+ if (robj.behind_desk) {
+ removeCSSClass(e3.parentNode, 'hideme');
+ util.widgets.set_text(e3, robj.behind_desk);
+ } else {
+ addCSSClass(e3.parentNode, 'hideme');
+ }
+ }
+ if (under_btn) {
+ var str = robj.ready + '/' + robj.total;
+ if (robj.behind_desk) {
+ str += ' (' + robj.behind_desk + ')';
+ under_btn.setAttribute(
+ 'tooltiptext', patronStrings.getString(
+ 'staff.patron.summary.hold_counts_behind_desk')
+ );
+ } else {
+ under_btn.setAttribute(
+ 'tooltiptext', patronStrings.getString(
+ 'staff.patron.summary.hold_counts')
+ );
+ }
+ util.widgets.set_text(under_btn, str);
+ }
obj.holds_summary = robj;
if (obj.holds_summary && obj.bills_summary)
if (typeof window.xulG == 'object' && typeof window.xulG.stop_sign_page == 'function')
value="&staff.patron_display.holds_available.label;" />
<description id="patron_holds_available" class="copyable holds_ready value subgroup" />
</row>
+ <row class='hideme'>
+ <label id="PatronSummaryStatus_holds_available_behind_desk_label" class="copyable text_right holds_ready label subgroup"
+ value="&staff.patron_display.holds_available_behind_desk.label;" />
+ <description id="patron_holds_available_behind_desk" class="copyable holds_ready value subgroup" />
+ </row>
<row id="pdsgr2" class="hide_patron_credit" hidden="true">
<label id="PatronSummaryStatus_credit_label" class="copyable text_left credit label"
value="&staff.patron_display.credit.label;" />
--- /dev/null
+Per-Hold Behind Desk Setting
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The value for behind-the-desk pickup is now stored directly on each
+hold request. This allows the system to better track the true location
+of captured hold items in cases where the patron setting has changed since
+hold capture.
+
+For these features to be accessible, the "Behind Desk Pickup Supported"
+(circ.holds.behind_desk_pickup_supported) org unit setting must be set
+to true.
+
+Staff Client
+++++++++++++
+
+In addition to the counts of ready for pickup and available holds, the
+staff client now also displays the number of behind the desk holds ready
+for pickup at the staff's working location. If no items are held behind
+the desk, this information does not display, in particular, because this
+information is useless if behind the desk holds are not supported at the
+staff's working location.
+
+TPAC Changes
+++++++++++++
+
+The system also allows patrons to set their own behind-the-desk
+pickup preferences in the TPAC settings interface. To activate this
+feature, admins need to set the Opac Visible flag to "true" for the
+"Hold is behind Circ Desk" (circ.holds_behind_desk) user setting and
+"Behind Desk Pickup Supported" must be set to true for the patron's
+home library.
+