# permission to override? XXX Should the permission check be scoped to a
# given org_unit context?
sub test_could_override {
- my ($self) = @_;
- my $event = $self->ctx->{"hold_failed_event"};
+ my ($self, $event) = @_;
return 0 unless $event;
- return 1 if $self->editor->allowed($event . ".override");
+ return 1 if $self->editor->allowed($event->{textcode} . ".override");
return 1 if $event->{"fail_part"} and
$self->editor->allowed($event->{"fail_part"} . ".override");
return 0;
# Find out whether we care that local copies are available
sub local_avail_concern {
- my ($self, $allowed, $hold_target, $hold_type, $pickup_lib) = @_;
+ my ($self, $hold_target, $hold_type, $pickup_lib) = @_;
my $would_block = $self->ctx->{get_org_setting}->
($pickup_lib, "circ.holds.hold_has_copy_at.block");
not $self->cgi->param("override")
) unless $would_block;
- if ($allowed->{"success"} and ($would_block or $would_alert)) {
+ if ($would_block or $would_alert) {
my $args = {
"hold_target" => $hold_target,
"hold_type" => $hold_type,
my $gos = $ctx->{get_org_setting};
my $e = $self->editor;
my $cgi = $self->cgi;
- $self->ctx->{page} = 'place_hold';
- $ctx->{hold_target} = $cgi->param('hold_target');
+ $self->ctx->{page} = 'place_hold';
+ my @targets = $cgi->param('hold_target');
$ctx->{hold_type} = $cgi->param('hold_type');
-
$ctx->{default_pickup_lib} = $e->requestor->home_ou; # unless changed below
+ $logger->info("Looking at hold targets: @targets");
+
+ # if the staff client provides a patron barcode, fetch the patron
if (my $bc = $self->cgi->cookie("patron_barcode")) {
- # passed in from staff client
$ctx->{patron_recipient} = $U->simplereq(
"open-ils.actor", "open-ils.actor.user.fleshed.retrieve_by_barcode",
$self->editor->authtoken, $bc
- ) or return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
+ ) or return Apache2::Const::HTTP_BAD_REQUEST;
$ctx->{default_pickup_lib} = $ctx->{patron_recipient}->home_ou;
}
my $request_lib = $e->requestor->ws_ou;
+ my @hold_data;
+ $ctx->{hold_data} = \@hold_data;
+
+ my $type_dispatch = {
+ T => sub {
+ my $recs = $e->batch_retrieve_biblio_record_entry(\@targets, {substream => 1});
+ for my $id (@targets) { # force back into the correct order
+ my ($rec) = grep {$_->id eq $id} @$recs;
+ push(@hold_data, {target => $rec, record => $rec});
+ }
+ },
+ V => sub {
+ my $vols = $e->batch_retrieve_asset_call_number([
+ \@targets, {
+ "flesh" => 1,
+ "flesh_fields" => {"acn" => ["record"]}
+ }
+ ], {substream => 1});
- # XXX check for failure of the retrieve_* methods called below, and
- # possibly replace all the if,elsif with a dispatch table (meh, elegance)
-
- my $target_field;
- if ($ctx->{hold_type} eq 'T') {
- $target_field = "titleid";
- $ctx->{record} = $e->retrieve_biblio_record_entry($ctx->{hold_target});
- } elsif ($ctx->{hold_type} eq 'V') {
- $target_field = "volume_id";
- my $vol = $e->retrieve_asset_call_number([
- $ctx->{hold_target}, {
- "flesh" => 1,
- "flesh_fields" => {"acn" => ["record"]}
+ for my $id (@targets) {
+ my ($vol) = grep {$_->id eq $id} @$vols;
+ push(@hold_data, {target => $vol, record => $vol->record});
}
- ]);
- $ctx->{record} = $vol->record;
- } elsif ($ctx->{hold_type} eq 'C') {
- $target_field = "copy_id";
- my $copy = $e->retrieve_asset_copy([
- $ctx->{hold_target}, {
- "flesh" => 2,
- "flesh_fields" => {
- "acn" => ["record"],
- "acp" => ["call_number"]
+ },
+ C => sub {
+ my $copies = $e->batch_retrieve_asset_copy([
+ \@targets, {
+ "flesh" => 2,
+ "flesh_fields" => {
+ "acn" => ["record"],
+ "acp" => ["call_number"]
+ }
}
+ ], {substream => 1});
+
+ for my $id (@targets) {
+ my ($copy) = grep {$_->id eq $id} @$copies;
+ push(@hold_data, {target => $copy, record => $copy->call_number->record});
}
- ]);
- $ctx->{record} = $copy->call_number->record;
- } elsif ($ctx->{hold_type} eq 'I') {
- $target_field = "issuanceid";
- my $iss = $e->retrieve_serial_issuance([
- $ctx->{hold_target}, {
- "flesh" => 2,
- "flesh_fields" => {
- "siss" => ["subscription"], "ssub" => ["record_entry"]
+ },
+ I => sub {
+ my $isses = $e->batch_retrieve_serial_issuance([
+ \@targets, {
+ "flesh" => 2,
+ "flesh_fields" => {
+ "siss" => ["subscription"], "ssub" => ["record_entry"]
+ }
}
+ ], {substream => 1});
+
+ for my $id (@targets) {
+ my ($iss) = grep {$_->id eq $id} @$isses;
+ push(@hold_data, {target => $iss, record => $iss->subscription->record_entry});
}
- ]);
- $ctx->{record} = $iss->subscription->record_entry;
- }
- # ...
+ }
+ # ...
- $ctx->{marc_xml} = XML::LibXML->new->parse_string($ctx->{record}->marc);
+ }->{$ctx->{hold_type}}->();
- if (my $pickup_lib = $cgi->param('pickup_lib')) {
- my $requestor = $e->requestor->id;
- my $usr;
+ # caller sent bad target IDs or the wrong hold type
+ return Apache2::Const::HTTP_BAD_REQUEST unless @hold_data;
- if ((not $ctx->{"is_staff"}) or
- ($cgi->param("hold_usr_is_requestor"))) {
- $usr = $requestor;
- } else {
- my $actor = create OpenSRF::AppSession("open-ils.actor");
- $usr = $actor->request(
- "open-ils.actor.user.retrieve_id_by_barcode_or_username",
- $e->authtoken, $cgi->param("hold_usr")
- )->gather(1);
-
- if (defined $U->event_code($usr)) {
- $ctx->{hold_failed} = 1;
- $ctx->{hold_failed_event} = $usr;
- }
- $actor->kill_me;
- }
+ # generate the MARC xml for each record
+ $_->{marc_xml} = XML::LibXML->new->parse_string($_->{record}->marc) for @hold_data;
- my $args = {
- patronid => $usr,
- $target_field => $ctx->{"hold_target"},
- pickup_lib => $pickup_lib,
- hold_type => $ctx->{"hold_type"},
- depth => 0, # XXX
- };
+ my $pickup_lib = $cgi->param('pickup_lib');
+ # no pickup lib means no holds placement
+ return Apache2::Const::OK unless $pickup_lib;
- my $allowed = $U->simplereq(
- 'open-ils.circ',
- 'open-ils.circ.title_hold.is_possible',
- $e->authtoken, $args
- );
+ $ctx->{hold_attempt_made} = 1;
- $logger->info('hold permit result ' . OpenSRF::Utils::JSON->perl2JSON($allowed));
+ # Give the original CGI params back to the user in case they
+ # want to try to override something.
+ $ctx->{orig_params} = $cgi->Vars;
+ delete $ctx->{orig_params}{submit};
+ delete $ctx->{orig_params}{hold_target};
- my ($local_block, $local_alert) = $self->local_avail_concern(
- $allowed, $args->{$target_field}, $args->{hold_type}, $pickup_lib
- );
+ my $usr = $e->requestor->id;
- # Give the original CGI params back to the user in case they
- # want to try to override something.
- $ctx->{orig_params} = $cgi->Vars;
+ if ($ctx->{is_staff} and !$cgi->param("hold_usr_is_requestor")) {
+ # find the real hold target
- if ($local_block) {
+ $usr = $U->simplereq(
+ 'open-ils.actor',
+ "open-ils.actor.user.retrieve_id_by_barcode_or_username",
+ $e->authtoken, $cgi->param("hold_usr"));
+
+ if (defined $U->event_code($usr)) {
$ctx->{hold_failed} = 1;
- $ctx->{hold_local_block} = 1;
+ $ctx->{hold_failed_event} = $usr;
+ }
+ }
+
+ # First see if we should warn/block for any holds that
+ # might have locally available items.
+ for my $hdata (@hold_data) {
+ my ($local_block, $local_alert) = $self->local_avail_concern(
+ $hdata->{target}->id, $ctx->{hold_type}, $pickup_lib);
+
+ if ($local_block) {
+ $hdata->{hold_failed} = 1;
+ $hdata->{hold_local_block} = 1;
} elsif ($local_alert) {
- $ctx->{hold_failed} = 1;
- $ctx->{hold_local_alert} = 1;
- } elsif ($allowed->{success}) {
- my $hold = Fieldmapper::action::hold_request->new;
-
- $hold->pickup_lib($pickup_lib);
- $hold->requestor($requestor);
- $hold->usr($usr);
- $hold->target($ctx->{hold_target});
- $hold->hold_type($ctx->{hold_type});
- # frozen, expired, etc..
-
- my $method = "open-ils.circ.holds.create";
- $method .= ".override" if $cgi->param("override");
-
- my $stat = $U->simplereq(
- "open-ils.circ", $method, $e->authtoken, $hold
- );
+ $hdata->{hold_failed} = 1;
+ $hdata->{hold_local_alert} = 1;
+ }
+ }
- # The following did not cover all the possible return values of
- # open-ils.circ.holds.create
- #if($stat and $stat > 0) {
- if ($stat and (not ref $stat) and $stat > 0) {
- # if successful, return the user to the requesting page
- $self->apache->log->info(
- "Redirecting back to " . $cgi->param('redirect_to')
- );
-
- # We also clear the patron_barcode (from the staff client)
- # cookie at this point (otherwise it haunts the staff user
- # later). XXX todo make sure this is best; also see that
- # template when staff mode calls xulG.opac_hold_placed()
- return $self->generic_redirect(
- undef,
- $self->cgi->cookie(
- -name => "patron_barcode",
- -path => "/",
- -secure => 1,
- -value => "",
- -expires => "-1h"
- )
- );
- } else {
- $ctx->{hold_failed} = 1;
+ my $method = 'open-ils.circ.holds.test_and_create.batch';
+ $method .= '.override' if $cgi->param('override');
+
+ my @create_targets = map {$_->{target}->id} (grep { !$_->{hold_failed} } @hold_data);
- delete $ctx->{orig_params}{submit};
+ if(@create_targets) {
+
+ my $bses = OpenSRF::AppSession->create('open-ils.circ');
+ my $breq = $bses->request(
+ $method,
+ $e->authtoken,
+ { patronid => $usr,
+ pickup_lib => $pickup_lib,
+ hold_type => $ctx->{hold_type}
+ },
+ \@create_targets
+ );
+
+ while (my $resp = $breq->recv) {
+
+ $resp = $resp->content;
+ $logger->info('batch hold placement result: ' . OpenSRF::Utils::JSON->perl2JSON($resp));
+
+ if ($U->event_code($resp)) {
+ $ctx->{general_hold_error} = $resp;
+ last;
+ }
- if (ref $stat eq 'ARRAY') {
- $ctx->{hold_failed_event} = shift @$stat;
- } elsif (defined $U->event_code($stat)) {
- $ctx->{hold_failed_event} = $stat;
+ my ($hdata) = grep {$_->{target}->id eq $resp->{target}} @hold_data;
+ my $result = $resp->{result};
+
+ if ($U->event_code($result)) {
+ # e.g. permission denied
+ $hdata->{hold_failed} = 1;
+ $hdata->{hold_failed_event} = $result;
+
+ } else {
+
+ if(not ref $result and $result > 0) {
+ # successul hold returns the hold ID
+
+ $hdata->{hold_success} = $result;
+
} else {
- $self->apache->log->info(
- "attempt to create hold returned $stat"
- );
+ # hold-specific failure event
+ $hdata->{hold_failed} = 1;
+ $hdata->{hold_failed_event} = $result->{last_event};
+ $hdata->{could_override} = $self->test_could_override($hdata->{hold_failed_event});
}
-
- $ctx->{could_override} = $self->test_could_override;
}
- } else { # hold *check* failed
- $ctx->{hold_failed} = 1; # XXX process the events, etc
- $ctx->{hold_failed_event} = $allowed->{last_event};
}
- # hold permit failed
+ $bses->kill_me;
}
+ # stay on the current page and display the results
+ return Apache2::Const::OK if
+ (grep {$_->{hold_failed}} @hold_data) or $ctx->{general_hold_error};
+
+ # if successful, do some cleanup and return the
+ # user to the requesting page.
+
+ # We also clear the patron_barcode (from the staff client)
+ # cookie at this point (otherwise it haunts the staff user
+ # later). XXX todo make sure this is best; also see that
+ # template when staff mode calls xulG.opac_hold_placed()
+ return $self->generic_redirect(
+ undef,
+ $self->cgi->cookie(
+ -name => "patron_barcode",
+ -path => "/",
+ -secure => 1,
+ -value => "",
+ -expires => "-1h"
+ )
+ );
+
return Apache2::Const::OK;
}
}
-# actions are create, delete, show, hide, rename, add_rec, delete_item
+# actions are create, delete, show, hide, rename, add_rec, delete_item, place_hold
# CGI is action, list=list_id, add_rec/record=bre_id, del_item=bucket_item_id, name=new_bucket_name
sub load_myopac_bookbag_update {
- my ($self, $action, $list_id) = @_;
+ my ($self, $action, $list_id, @hold_recs) = @_;
my $e = $self->editor;
my $cgi = $self->cgi;
$list_id ||= $cgi->param('list');
my @add_rec = $cgi->param('add_rec') || $cgi->param('record');
- my @del_item = $cgi->param('del_item');
+ my @selected_item = $cgi->param('selected_item');
my $shared = $cgi->param('shared');
my $name = $cgi->param('name');
my $success = 0;
$success = $U->simplereq('open-ils.actor',
'open-ils.actor.container.create', $e->authtoken, 'biblio', $list)
+ } elsif($action eq 'place_hold') {
+
+ # @hold_recs comes from anon lists redirect; selected_itesm comes from existing buckets
+ unless (@hold_recs) {
+ if (@selected_item) {
+ my $items = $e->search_container_biblio_record_entry_bucket_item({id => \@selected_item});
+ @hold_recs = map { $_->target_biblio_record_entry } @$items;
+ }
+ }
+
+ return Apache2::Const::OK unless @hold_recs;
+ $logger->info("placing holds from list page on: @hold_recs");
+
+ my $url = $self->ctx->{opac_root} . '/place_hold?hold_type=T';
+ $url .= ';hold_target=' . $_ for @hold_recs;
+ return $self->generic_redirect($url);
+
} else {
$list = $e->retrieve_container_biblio_record_entry_bucket($list_id);
}
} elsif($action eq 'del_item') {
- foreach (@del_item) {
+ foreach (@selected_item) {
$success = $U->simplereq(
'open-ils.actor',
'open-ils.actor.container.item.delete', $e->authtoken, 'biblio', $_
sub load_mylist_move {
my $self = shift;
my @rec_ids = $self->cgi->param('record');
+ my $action = $self->cgi->param('action') || '';
+
+ return $self->load_myopac_bookbag_update('place_hold', undef, @rec_ids)
+ if $action eq 'place_hold';
my ($cache_key, $list) = $self->fetch_mylist;
return $self->mylist_action_redirect unless $cache_key;
$cache_key, ANON_CACHE_MYLIST, \@keep
);
- if ($self->ctx->{user} and $self->cgi->param('action') =~ /^\d+$/) {
+ if ($self->ctx->{user} and $action =~ /^\d+$/) {
# in this case, action becomes list_id
$self->load_myopac_bookbag_update('add_rec', $self->cgi->param('action'));
# XXX TODO: test for failure of above
.results-paginator-selected { color: red; }
.inactive-hold { background: #e5e5e5; }
+
+#hold-items-list li { margin-bottom: 20px; }
+.hold-items-list-title { font-size: 120%; }
+.hold-items-list-problem { color: red; }
+
+.big-strong {font-weight: bold; font-size: 120%; }
<input type="checkbox" onclick="
var inputs=document.getElementsByTagName('input');
for (i = 0; i < inputs.length; i++) {
- if (inputs[i].name == 'del_item' && !inputs[i].disabled && inputs[i].getAttribute('bbag') == [% bbag.id %])
+ if (inputs[i].name == 'selected_item' && !inputs[i].disabled && inputs[i].getAttribute('bbag') == [% bbag.id %])
inputs[i].checked = this.checked;}"/>
</td>
<td width="1%" class="nowrap">
<select class="opac-auto-179" name="action">
<option>[% l('-- Actions for this list --') %]</option>
- <!-- XXX not ready yet<option value="hold">[% l('Place Hold') %]</option> -->
+ <option value="place_hold">[% l('Place Hold') %]</option>
<option value="del_item">[% l('Remove Items') %]</option>
</select>
<input type="submit" value="[% l('Go') %]" />
attrs = {marc_xml => ctx.bookbags_marc_xml.$rec_id};
PROCESS get_marc_attrs args=attrs %]
<tr>
- <td class="item_list_padding" style="padding-left: 10px;"><input type="checkbox" name="del_item" value="[% item.id %]" bbag='[% bbag.id %]'/></td>
+ <td class="item_list_padding" style="padding-left: 10px;"><input type="checkbox" name="selected_item" value="[% item.id %]" bbag='[% bbag.id %]'/></td>
<td class="item_list_padding" style="padding-left: 5px;">[% attrs.title | html %]</td>
<td class="item_list_padding">[% attrs.author | html %]</td>
</tr>
<td width="1%" class="nowrap">
<select class="opac-auto-179" name="action">
<option>[% l('-- Actions for this list --') %]</option>
- <!-- XXX not ready <option value="hold">[% l('Place Hold') %]</option> -->
+ <option value="place_hold">[% l('Place Hold') %]</option>
<option value="delete">[% l('Remove Items') %]</option>
[% IF ctx.user AND ctx.bookbags.size %]
<optgroup label="Move selected items to">
[% PROCESS "default/opac/parts/misc_util.tt2";
- attrs = {marc_xml => ctx.marc_xml};
- PROCESS get_marc_attrs args=attrs;
-
PROCESS "default/opac/parts/hold_error_messages.tt2";
%]
-<div>
- <div id='holds_box' class='canvas' style='margin-top: 6px;'>
- [% IF ctx.hold_success %]
- <div><big><strong>[% l("Hold was successfully placed"); %]</strong></big></div>
- [% ELSIF ctx.hold_failed %]
- <div><big><strong>[% l("Hold was not successfully placed"); %]</strong></big></div>
- [% IF ctx.hold_local_block %]
- <div>[% l("There is already a copy available at your local library.") %]</div>
- [% ELSIF ctx.hold_failed_event || ctx.hold_local_alert %]
- <div>
- <strong>[% l('Problem:') %]</strong>
- <span title="[% ctx.hold_failed_event.textcode | html %]">
- <em>[%
- fail_part_key = ctx.hold_failed_event.payload.fail_part;
- event_key = ctx.hold_failed_event.textcode;
-
- # display:
- l(FAIL_PART_MSG_MAP.$fail_part_key) ||
- l(EVENT_MSG_MAP.$event_key) ||
- l(ctx.hold_failed_event.desc) ||
- ctx.hold_failed_event.payload.fail_part ||
- ctx.hold_failed_event.textcode ||
- (ctx.hold_local_alert ?
- l("There is already a copy available at your local library.") :
- l("Unknown problem")) %]</em>
- </span>
- [% IF ctx.hold_copy_available %]<p>
- [% l('Find a copy in the shelving location, "[_1]."', locname) | html %]
- </p>[% END %]
-
- [% IF ctx.could_override || ctx.hold_local_alert %]
- <p>
- <big>[% l("You have permission to place this hold anyway.") %]</big>
- <br />
- [% l("Click submit below to override the system's objection and place your hold.") %]
- </p>
- <form method="POST">
- <input type="hidden" type="name" name="override" value="1" />
- [% FOR k IN ctx.orig_params.keys %]
- <input type="hidden" name="[% k %]" value="[% ctx.orig_params.$k | uri %]" />
- [% END %]
- <input type="image" name="submit" value="submit" title="[% l('Submit') %]"
- alt="[% l('Submit') %]" src="[% ctx.media_prefix %]/images/btnSubmit.png" />
- </form>
- [% END %]
- </div>
- [% END;
- ELSIF ctx.hold_local_block;
- l("There is already a copy available at your local library");
- ELSE %]
- <form method="POST">
- <br/>
- <input type="hidden" name="hold_target"
- value="[% CGI.param('hold_target') | html %]" />
- <input type="hidden" name="hold_type"
- value="[% CGI.param('hold_type') | html %]" />
- [%
- new_redirect_to = ctx.referer;
- IF new_redirect_to.match('redirect_to');
- new_redirect_to = 'https://' _ ctx.hostname _ ctx.opac_root _ '/home';
- ELSE;
- new_redirect_to = new_redirect_to | replace('^http:', 'https:');
- END;
- %]
- <input type="hidden" name="redirect_to"
- value="[% new_redirect_to | html %]" />
- <h1>Place Hold</h1>
- [% IF ctx.is_staff %]
- <p class="staff-hold">
- <input type="radio" id="hold_usr_is_requestor_not"
+<div id='holds_box' class='canvas' style='margin-top: 6px;'>
+ <h1>[% l('Place Hold') %]</h1>
+ <form method="POST">
+ <input type="hidden" name="hold_type" value="[% CGI.param('hold_type') | html %]" />
+ [%#
+ new_redirect_to = ctx.referer;
+ IF new_redirect_to.match('redirect_to');
+ new_redirect_to = 'https://' _ ctx.hostname _ ctx.opac_root _ '/home';
+ ELSE;
+ new_redirect_to = new_redirect_to | replace('^http:', 'https:');
+ END;
+ %]
+ <input type="hidden" name="redirect_to" value="[% CGI.param('redirect_to') || CGI.referer | html %]" />
+
+ [% IF ctx.is_staff %]
+ <p class="staff-hold">
+ <input type="radio" id="hold_usr_is_requestor_not"
+ onchange="staff_hold_usr_input_disabler(this);"
+ name="hold_usr_is_requestor" value="0"
+ [% IF ctx.patron_recipient; ' checked="checked"'; END %] />
+ <label for="hold_usr_is_requestor_not">
+ [% l("Place hold for patron by barcode:") %]
+ </label>
+ <input type="text" name="hold_usr" id="hold_usr_input" value="[% ctx.patron_recipient.card.barcode | html %]" /><br />[%# XXX multi-barcode users? %]
+ <span>
+ <input type="radio" id="hold_usr_is_requestor"
onchange="staff_hold_usr_input_disabler(this);"
- name="hold_usr_is_requestor" value="0"
- [% IF ctx.patron_recipient; ' checked="checked"'; END %]
- />
- <label for="hold_usr_is_requestor_not">
- [% l("Place hold for patron by barcode:") %]
+ name="hold_usr_is_requestor" value="1" />
+ <label for="hold_usr_is_requestor">
+ [% l("Place this hold for me ([_1] [_2])", ctx.user.first_given_name, ctx.user.family_name) | html %]
</label>
- <input type="text" name="hold_usr" id="hold_usr_input" value="[% ctx.patron_recipient.card.barcode | html %]" /><br />[%# XXX multi-barcode users? %]
- <span>
- <input type="radio" id="hold_usr_is_requestor"
- onchange="staff_hold_usr_input_disabler(this);"
- name="hold_usr_is_requestor" value="1" />
- <label for="hold_usr_is_requestor">
- [% l("Place this hold for me ([_1] [_2])", ctx.user.first_given_name, ctx.user.family_name) | html %]
- </label>
- </span>
- </p>
- [% END %]
- <p>
- [% title = attrs.title | html; libname = ctx.get_aou(ctx.default_pickup_lib).name | html %]
- [% | l(title, libname) %]
- You would like to place a hold on <strong><q>[_1]</q></strong>.<br />
- If this is correct, confirm your pickup location and click <strong>SUBMIT</strong>.
- [% END %]
- </p>
- <p>
- [% l('Pickup location:') %]
- [% PROCESS "default/opac/parts/org_selector.tt2";
- PROCESS build_org_selector name='pickup_lib' value=ctx.default_pickup_lib id='pickup_lib' can_have_vols_only=1 %]
- </p>
- <p>
- [% |l %]If you use the Traveling Library Center (TLC) and ABC Express
- services, please select "Outreach" to have the item delivered
- during your scheduled visit.[% END %]
- </p>
- <input type="image" name="submit" value="submit" title="[% l('Submit') %]"
- alt="[% l('Submit') %]" src="[% ctx.media_prefix %]/images/btnSubmit.png" />
-
- <a href="javascript:history.go(-1);" id="holds_cancel"><img
- alt="[% l('Cancel') %]" src="[% ctx.media_prefix %]/images/btnCancel.png" /></a>
- </form>
- <br /><br />
+ </span>
+ </p>
+ [% END %]
+
+ <!-- loop through the holds and display status of request where appropriate -->
+ <ul id='hold-items-list'>
+ [% FOR hdata IN ctx.hold_data;
+ attrs = {marc_xml => hdata.marc_xml};
+ PROCESS get_marc_attrs args=attrs %]
+ <li>
+ <input type="hidden" name="hold_target" value="[% hdata.target.id | html %]" />
+ <div class='hold-items-list-title'>[% attrs.title_extended | html %]</div>
+ </li>
+ [% END %]
+ </ul>
+
<p>
- [% |l %]* If you need your item today, and it is checked in at your
- library, please place your hold and then call your library to set it
- aside. Placing a hold without calling the library will increase your
- wait time.[% END %]
- <br /><a href="#">[% l('Library phone numbers.') %]</a>
+ [% l('Pickup location:') %]
+ [% PROCESS "default/opac/parts/org_selector.tt2";
+ PROCESS build_org_selector name='pickup_lib' value=ctx.default_pickup_lib id='pickup_lib' can_have_vols_only=1 %]
</p>
<p>
- [% |l %]* For best possible service, we recommend keeping
- a printed copy of your most recent holds list.[% END %]
+ [% |l %]If you use the Traveling Library Center (TLC) and ABC Express
+ services, please select "Outreach" to have the item delivered
+ during your scheduled visit.[% END %]
</p>
- [% END %] <!-- ctx.hold_success -->
- <table width='90%' border="1" class="hide_me">
- <tbody>
- <tr>
- <td class='holds_cell color_1'
- align='center' colspan='2'>[% l("Create / Edit a Hold") %]</td>
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Recipient") %]:</td>
- <td class='holds_cell' id='holds_recipient'> </td>
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Title:") %]</td>
- <!-- <td class='holds_cell' id='holds_title'> </td> -->
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Author") %]</td>
- <td class='holds_cell' id='holds_author'> </td>
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Format") %]</td>
- <td class='holds_cell' id='holds_format'> </td>
- </tr>
- <tr id='hold_physical_desc_row'>
- <td class='holds_cell'>[% l("Physical Description:") %]</td>
- <td class='holds_cell' id='holds_physical_desc'> </td>
- </tr>
-
- <tr class='hide_me' id='holds_cn_row'>
- <td class='holds_cell'>[% l("Call Number:") %]</td>
- <td class='holds_cell'><b id='holds_cn'/> </td>
- </tr>
-
- <tr class='hide_me' id='holds_copy_row'>
- <td class='holds_cell'>[% l("Copy Barcode:") %]</td>
- <td class='holds_cell'><b id='holds_copy'/> </td>
- </tr>
-
- <tr class='hide_me' id='holds_type_row'>
- <td class='holds_cell'>[% l("Hold Type:") %]</td>
- <td class='holds_cell hide_me' id='holds_is_cn'>
- <b>[% l("Volume Hold") %]</b>
- </td>
- <td class='holds_cell hide_me' id='holds_is_copy'>
- <b>[% l("Copy Hold") %]</b>
- </td>
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Contact telephone number") %]:</td>
- <td class='holds_cell'>
- <input id='holds_phone' size='13' maxlength='12'/>
- <span style='margin-left: 4px; font-size: 7pt;'>
- [% l("(XXX-YYY-ZZZZ)") %]
- </span>
- </td>
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Enable phone notifications for this hold?") %]</td>
- <td class='holds_cell'>
- <input type='checkbox' id='holds_enable_phone'
- checked='checked' />
- </td>
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Contact email address") %]:</td>
- <td class='holds_cell' id='holds_email'>
- <span class='hide_me' id='holds.no_email'>
- ([% l("Patron has no configured email address") %])<br/>
- ([% l("See") %] <a class='classic_link' id='holds.no_email.my_account'>[% l("My Account") %]</a> [% l("for setting your email address") %])
- </span>
- <span class='hide_me' id='holds.no_email.xul'>
- [% l("(Patron has no configured email address)") %]
- </span>
- </td>
- </tr>
- <tr>
- <td class='holds_cell'>[% l("Enable email notifications for this hold?") %]</td>
- <td class='holds_cell'>
- <input type='checkbox' id='holds_enable_email'
- checked='checked'/>
- </td>
- </tr>
- <!--
- <tr id='holds_depth_selector_row' class='hide_me'>
- <td class='holds_cell'>Hold Range</td>
- <td class='holds_cell'>
- <select id='holds_depth_selector'></select>
- </td>
- </tr>
- -->
- <tr>
- <td class='holds_cell'>[% l("Pickup location") %]</td>
- <td class='holds_cell'>
- <!-- <select id='holds_org_selector'> </select> -->
- </td>
- </tr>
-
- <tr>
- <td class='holds_cell'>[% l("Expiration date") %]</td>
- <td class='holds_cell'>
- <input size='10' maxlength='10'
- id='holds_expire_time' />
- </td>
- </tr>
-
- <tr>
- <td class='holds_cell'>
- [% l("Suspend this hold") %]
- <a class='classic_link'
- href='#'>[% l("(Help)") %]</a>
- </td>
- <td class='holds_cell'>
- <input type='checkbox' id='holds_frozen_chkbox' />
- </td>
- </tr>
- <tr id='hold_frozen_thaw_row' class='hide_me'>
- <td class='holds_cell'>
- <!-- XXX TODO there used to be script here dealing with
- frozen holds -->
- [% l("Automatically activate hold on:") %]
- </td>
- <td class='holds_cell'>
- <input size='10' maxlength='10'
- id='holds_frozen_thaw_input' />
- </td>
- </tr>
-
- <tr id='holds_alt_formats_row_extras' class='hide_me'>
- <td colspan='2' align='center'>
- <div style='padding: 8px;'>
- <a class='classic_link' href='#'
- style='padding: 5px;'>[% l("Advanced Hold Options") %]</a>
- </div>
- </td>
- </tr>
-
- <tr id='holds_alt_formats_row' class='hide_me'>
-
- <td class='holds_cell'>
- <div style='margin-bottom: 5px;'>
- <span>[% l("Acceptable Alternative Formats:") %] </span>
- <span><a class='classic_link red' href='#'>[% l("(Help)") %]</a></span>
- </div>
- <div>[% l("(control-click to select multiple formats)") %]</div>
- </td>
-
- <td class='holds_cell'>
- <select id='hold_alt_form_selector' multiple='multiple' style='width: 14em;'>
- <option value='at' class='hide_me'>[% l("Books") %]</option>
- <option value='at-d' class='hide_me'>[% l("Large Print Books") %]</option>
- <option value='i' class='hide_me'>[% l("Audiobooks") %]</option>
- <option value='g' class='hide_me'>[% l("Video Recordings") %]</option>
- <option value='j' class='hide_me'>[% l("Music") %]</option>
- </select>
- </td>
- </tr>
- <tr>
- <td class='holds_cell' align='center' colspan='2'>
- <!-- <button id='holds_submit'>[% l("Place Hold") %]</button> -->
- <button class='hide_me' id='holds_update'>[% l("Update Hold") %]</button>
- <span style='padding: 20px;'> </span>
- <!-- <button id='holds_cancel'>[% l("Cancel") %]</button> -->
- </td>
- </tr>
- </tbody>
- </table>
- <span class='hide_me' id='holds_bad_phone'>
- [% l("The phone number does not have the correct format. The expected format is XXX-YYY-ZZZZ") %]
- </span>
- <span class='hide_me' id='hold_not_allowed'>
- [% |l %]No items were found that could fulfill the requested holds.
- It's possible that choosing a different format will result in a successful hold.
- It is also possible that you have exceeded the number of allowable holds.
- For further information, please consult your local librarian.[% END %]
- </span>
- </div>
- <div id="anonListTable" class="hide_me" style="margin-top: 6px;">
- <select id="holdsCacheSel" class="hide_me"></select><br />
- <a href="#">Place hold on selected</a><br />
- <a href="#">Remove selected</a>
-
- <table id="temp_list_holds" cellpadding='0' cellspacing='0' border='0'
- style="margin-top:10px;">
- <tr>
- <td width="1%" style="padding-left:10px;">
- <input type='checkbox' title='Select All'
- id='anon_selector' />
- </td>
- <td width="1%">
- </td>
- <td width="98%" style="padding-left:40px;">
- <strong>Title</strong>
- </td>
- </tr>
- </table>
- <table width='100%' style="margin-left:7px;margin-bottom:10px;">
- <thead>
- <tr><td width='20'></td><td width='30'></td><td></td></tr>
- </thead>
- <tbody id="anonListParent">
- <tr id="anonListTemp">
- <td><input type='checkbox' name='anon_selector' /></td>
- <td name="curr_row"></td>
- <td name="title"></td>
- </tr>
- </tbody>
- </table>
- <a href="#">Back to search results</a>
- </div>
-
- <span class='hide_me' id='format_words'>
- <span name='at'>[% l("Books") %]</span>
- <span name='at-d'>[% l("Large Print Books") %]</span>
- <span name='i'>[% l("Audiobooks") %]</span>
- <span name='g'>[% l("Video Recordings") %]</span>
- <span name='j'>[% l("Music") %]</span>
- <span name='m'>[% l("Electronic Resources") %]</span>
- </span>
-
- <span class='hide_me' id='holds_explain_adv'>
- [% |l %]If you wish to broaden the scope of your hold to include other versions of this title,
- select the formats that would be acceptable. The first available copy will be sent to you.[% END %]
- </span>
-
- <span class='hide_me' id='holds_pick_good_org'>[% l("Please select a physical location where your hold can be delivered.") %]</span>
- <span class='hide_me' id='hold_dup_exists'>[% l("A hold already exists on the requested item.") %]</span>
- <span class='hide_me' id='hold_dup_exists_override'>[% l("A hold already exists on the requested item. Would you like to create the hold anyway?") %]</span>
-
- <span id='hold_failed_patron_barred' class='hide_me'>
- [% |l %]PATRON BARRED. Please see any notes in the "Staff Notes" section of your
- "My Account" page or contact your local library.[% END %]
- </span>
-
- <span id='invalid_hold' class='hide_me'>
- [% |l %]This hold is no longer valid. It's likely that the target for the hold was
- deleted from the system. Please cancel this hold and place a new one.[% END %]
- </span>
- <span id='holds_invalid_recipient' class='hide_me'>[% l("The patron barcode entered as the hold recipient is invalid.") %]</span>
+ <input type="image" name="submit" value="submit" title="[% l('Submit') %]"
+ alt="[% l('Submit') %]" src="[% ctx.media_prefix %]/images/btnSubmit.png" />
+
+ <a href="javascript:history.go(-1);" id="holds_cancel"><img
+ alt="[% l('Cancel') %]" src="[% ctx.media_prefix %]/images/btnCancel.png" /></a>
+ </form>
+ <br /><br />
+ <p>
+ [% |l %]* If you need your item today, and it is checked in at your
+ library, please place your hold and then call your library to set it
+ aside. Placing a hold without calling the library will increase your
+ wait time.[% END %]
+ <br /><a href="#">[% l('Library phone numbers.') %]</a>
+ </p>
+ <p>
+ [% |l %]* For best possible service, we recommend keeping
+ a printed copy of your most recent holds list.[% END %]
+ </p>
</div>
+
--- /dev/null
+[% PROCESS "default/opac/parts/misc_util.tt2";
+ PROCESS "default/opac/parts/hold_error_messages.tt2";
+ override_ok = [];
+ fail_count = 0;
+%]
+
+<!-- TODO: CSS for big/strong-->
+
+<div id='holds_box' class='canvas' style='margin-top: 6px;'>
+ <h1>[% l('Place Hold') %]</h1>
+
+ <ul id='hold-items-list'>
+
+ [% FOR hdata IN ctx.hold_data;
+ attrs = {marc_xml => hdata.marc_xml};
+ PROCESS get_marc_attrs args=attrs %]
+ <li>
+ <div class='hold-items-list-title'>[% attrs.title_extended | html %]</div>
+ <div>
+ [% IF hdata.hold_success %]
+
+ <div>[% l("Hold was successfully placed"); %]</div>
+
+ [% ELSIF hdata.hold_failed;
+ fail_count = fail_count + 1 %]
+
+
+ <div><big><strong>[% l("Hold was not successfully placed"); %]</strong></big></div>
+ [% IF hdata.hold_local_block %]
+ <div>[% l("There is already a copy available at your local library.") %]</div>
+ [% ELSIF hdata.hold_failed_event || hdata.hold_local_alert %]
+ <div>
+ <span class='hold-items-list-problem'>[% l('Problem:') %]</span>
+ <span title="[% hdata.hold_failed_event.textcode | html %]">
+ <em>[%
+ fail_part_key = hdata.hold_failed_event.payload.fail_part;
+ event_key = hdata.hold_failed_event.textcode;
+
+ # display:
+ l(FAIL_PART_MSG_MAP.$fail_part_key) ||
+ l(EVENT_MSG_MAP.$event_key) ||
+ l(hdata.hold_failed_event.desc) ||
+ hdata.hold_failed_event.payload.fail_part ||
+ hdata.hold_failed_event.textcode ||
+ (hdata.hold_local_alert ?
+ l("There is already a copy available at your local library.") :
+ l("Unknown problem")) | html
+ %]</em>
+ [% IF event_key == 'PERM_FAILURE' %]
+ <div>[% l('Permission: "[_1]"', hdata.hold_failed_event.ilsperm) | html %]</div>
+ [% END %]
+ </span>
+
+ [% IF hdata.hold_copy_available %]
+ <p>[% l('Find a copy in the shelving location, "[_1]."', locname) | html %]</p>
+ [% END %]
+
+ [% IF hdata.could_override || hdata.hold_local_alert %]
+ [% override_ok.push(hdata.target.id) %]
+ <p>
+ <big>[% l("You have permission to place this hold anyway.") %]</big>
+ <br />
+ [% l("Click submit below to override and place your hold.") %]
+ </p>
+ <form method="POST">
+ <input type="hidden" type="name" name="override" value="1" />
+ <input type="hidden" name="hold_target" value="[% hdata.target.id | html %]" />
+ [% FOR k IN ctx.orig_params.keys %]
+ <input type="hidden" name="[% k %]" value="[% ctx.orig_params.$k | html %]" />
+ [% END %]
+ <input type="image" name="submit" value="submit" title="[% l('Submit') %]"
+ alt="[% l('Submit') %]" src="[% ctx.media_prefix %]/images/btnSubmit.png" />
+ </form>
+ [% END %]
+ </div>
+ [% ELSIF hdata.hold_local_block;
+ l("There is already a copy available at your local library");
+ END;
+ END %]
+ </div>
+ </li>
+ [% END %]
+ <div>
+ [% IF fail_count > 1 AND fail_count == override_ok.size %]
+ <hr/>
+ <form method="POST">
+ <input type="hidden" type="name" name="override" value="1" />
+ [% FOR k IN ctx.orig_params.keys %]
+ <input type="hidden" name="[% k %]" value="[% ctx.orig_params.$k | html %]" />
+ [% END %]
+ [% FOR target IN override_ok %]
+ <input type="hidden" name="hold_target" value="[% target | html %]" />
+ [% END %]
+ <div class='big-strong'>[% l('Override all holds') %]</div>
+ <br/>
+ <input type="image" name="submit" value="submit" title="[% l('Submit') %]"
+ alt="[% l('Submit') %]" src="[% ctx.media_prefix %]/images/btnSubmit.png" />
+ </form>
+ [% END %]
+ </div>
+ </ul>
+</div>
+
<div id="content-wrapper">
<div id="main-content">
<div class="common-full-pad"></div>
- [% INCLUDE "default/opac/parts/place_hold.tt2" %]
+ [% IF ctx.hold_attempt_made %]
+ [% INCLUDE "default/opac/parts/place_hold_result.tt2" %]
+ [% ELSE %]
+ [% INCLUDE "default/opac/parts/place_hold.tt2" %]
+ [% END %]
<div class="common-full-pad"></div>
</div>
</div>