[open-ils-commits] r18232 - in branches/rel_2_0/Open-ILS: src/perlmods/OpenILS/Application/Circ web/opac/extras/circ (senator)
svn at svn.open-ils.org
svn at svn.open-ils.org
Thu Oct 7 18:48:12 EDT 2010
Author: senator
Date: 2010-10-07 18:48:12 -0400 (Thu, 07 Oct 2010)
New Revision: 18232
Added:
branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.js
Modified:
branches/rel_2_0/Open-ILS/src/perlmods/OpenILS/Application/Circ/Holds.pm
branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.html
Log:
Backport r18230 and 18231, hold shelf clearer/printer
Modified: branches/rel_2_0/Open-ILS/src/perlmods/OpenILS/Application/Circ/Holds.pm
===================================================================
--- branches/rel_2_0/Open-ILS/src/perlmods/OpenILS/Application/Circ/Holds.pm 2010-10-07 22:46:24 UTC (rev 18231)
+++ branches/rel_2_0/Open-ILS/src/perlmods/OpenILS/Application/Circ/Holds.pm 2010-10-07 22:48:12 UTC (rev 18232)
@@ -34,6 +34,8 @@
use DateTime;
use DateTime::Format::ISO8601;
use OpenSRF::Utils qw/:datetime/;
+use Digest::MD5 qw(md5_hex);
+use OpenSRF::Utils::Cache;
my $apputils = "OpenILS::Application::AppUtils";
my $U = $apputils;
@@ -1407,7 +1409,7 @@
(@$sort ? (order_by => $sort) : ()),
($$params{limit} ? (limit => $$params{limit}) : ()),
($$params{offset} ? (offset => $$params{offset}) : ())
- }, {"subquery" => 1}
+ }, {"substream" => 1}
) or return $e->die_event;
$logger->info("about to stream back " . scalar(@$holds_ids) . " holds");
@@ -2754,7 +2756,87 @@
return ( $U->record_to_mvr($title), $volume, $copy, $issuance );
}
+__PACKAGE__->register_method(
+ method => 'clear_shelf_cache',
+ api_name => 'open-ils.circ.hold.clear_shelf.get_cache',
+ stream => 1,
+ signature => {
+ desc => q/
+ Returns the holds processed with the given cache key
+ /
+ }
+);
+sub clear_shelf_cache {
+ my($self, $client, $auth, $cache_key, $chunk_size) = @_;
+ my $e = new_editor(authtoken => $auth, xact => 1);
+ return $e->die_event unless $e->checkauth and $e->allowed('VIEW_HOLD');
+
+ $chunk_size ||= 25;
+ my $hold_data = OpenSRF::Utils::Cache->new('global')->get_cache($cache_key);
+
+ if (!$hold_data) {
+ $logger->info("no hold data found in cache"); # XXX TODO return event
+ $e->rollback;
+ return undef;
+ }
+
+ my $maximum = 0;
+ foreach (keys %$hold_data) {
+ $maximum += scalar(@{ $hold_data->{$_} });
+ }
+ $client->respond({"maximum" => $maximum, "progress" => 0});
+
+ for my $action (sort keys %$hold_data) {
+ while (@{$hold_data->{$action}}) {
+ my @hid_chunk = splice @{$hold_data->{$action}}, 0, $chunk_size;
+
+ my $result_chunk = $e->json_query({
+ "select" => {
+ "acp" => ["barcode"],
+ "au" => [qw/
+ first_given_name second_given_name family_name alias
+ /],
+ "acn" => ["label"],
+ "bre" => ["marc"],
+ "acpl" => ["name"],
+ "ahr" => ["id"]
+ },
+ "from" => {
+ "ahr" => {
+ "acp" => {
+ "field" => "id", "fkey" => "current_copy",
+ "join" => {
+ "acn" => {
+ "field" => "id", "fkey" => "call_number",
+ "join" => {
+ "bre" => {
+ "field" => "id", "fkey" => "record"
+ }
+ }
+ },
+ "acpl" => {"field" => "id", "fkey" => "location"}
+ }
+ },
+ "au" => {"field" => "id", "fkey" => "usr"}
+ }
+ },
+ "where" => {"+ahr" => {"id" => \@hid_chunk}}
+ }, {"substream" => 1}) or return $e->die_event;
+
+ $client->respond([
+ map {
+ +{"action" => $action, "hold_details" => $_}
+ } @$result_chunk
+ ]);
+ }
+ }
+
+ $e->rollback;
+ return undef;
+}
+
+
__PACKAGE__->register_method(
method => 'clear_shelf_process',
stream => 1,
@@ -2776,6 +2858,7 @@
my $e = new_editor(authtoken=>$auth, xact => 1);
$e->checkauth or return $e->die_event;
+ my $cache = OpenSRF::Utils::Cache->new('global');
$org_id ||= $e->requestor->ws_ou;
$e->allowed('UPDATE_HOLD', $org_id) or return $e->die_event;
@@ -2793,8 +2876,9 @@
{ idlist => 1 }
);
-
my @holds;
+ my $chunk_size = 25; # chunked status updates
+ my $counter = 0;
for my $hold_id (@$hold_ids) {
$logger->info("Clear shelf processing hold $hold_id");
@@ -2821,52 +2905,48 @@
}
push(@holds, $hold);
+ $client->respond({maximum => scalar(@holds), progress => $counter}) if ( (++$counter % $chunk_size) == 0);
}
if ($e->commit) {
+ my %cache_data = (
+ hold => [],
+ transit => [],
+ shelf => []
+ );
+
for my $hold (@holds) {
my $copy = $hold->current_copy;
-
my ($alt_hold) = __PACKAGE__->find_nearest_permitted_hold($e, $copy, $e->requestor, 1);
if($alt_hold) {
- # copy is needed for a hold
- $client->respond({action => 'hold', copy => $copy, hold_id => $hold->id});
+ push(@{$cache_data{hold}}, $hold->id); # copy is needed for a hold
} elsif($copy->circ_lib != $e->requestor->ws_ou) {
- # copy needs to transit
- $client->respond({action => 'transit', copy => $copy, hold_id => $hold->id});
+ push(@{$cache_data{transit}}, $hold->id); # copy needs to transit
} else {
- # copy needs to go back to the shelf
- $client->respond({action => 'shelf', copy => $copy, hold_id => $hold->id});
+ push(@{$cache_data{shelf}}, $hold->id); # copy needs to go back to the shelf
}
}
+ my $cache_key = md5_hex(time . $$ . rand());
+ $logger->info("clear_shelf_cache: storing under $cache_key");
+ $cache->put_cache($cache_key, \%cache_data, 7200); # TODO: 2 hours. configurable?
+
# tell the client we're done
- $client->respond_complete;
+ $client->respond_complete({cache_key => $cache_key});
- # fire off the hold cancelation trigger
- my $trigger = OpenSRF::AppSession->connect('open-ils.trigger');
+ # fire off the hold cancelation trigger and wait for response so don't flood the service
+ $U->create_events_for_hook(
+ 'hold_request.cancel.expire_holds_shelf',
+ $_, $org_id, undef, undef, 1) for @holds;
- for my $hold (@holds) {
-
- my $req = $trigger->request(
- 'open-ils.trigger.event.autocreate',
- 'hold_request.cancel.expire_holds_shelf',
- $hold, $org_id);
-
- # wait for response so don't flood the service
- $req->recv;
- }
-
- $trigger->disconnect;
-
} else {
# tell the client we're done
$client->respond_complete;
Modified: branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.html
===================================================================
--- branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.html 2010-10-07 22:46:24 UTC (rev 18231)
+++ branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.html 2010-10-07 22:48:12 UTC (rev 18232)
@@ -8,13 +8,9 @@
@import url('/opac/skin/default/css/layout.css');
</style>
<style type="text/css">
- /* html, body {
- height: 100%;
- width: 100%;
- margin: 0px 0px 0px 0px;
- padding: 0px 0px 0px 0px;
- overflow: hidden;
- } */
+ #clear_holds_deck { margin-bottom: 1em; }
+ a { color: blue; text-decoration: underline; }
+ small { font-size: 9pt; }
body { font-size: 14pt; }
td {
padding-right: 1em;
@@ -44,180 +40,23 @@
<script type="text/javascript" src="/js/dojo/openils/AutoIDL.js"></script>
<script type="text/javascript" src="/js/dojo/openils/User.js"></script>
<script type="text/javascript" src="/js/dojo/openils/Util.js"></script>
+ <script type="text/javascript" src="/opac/extras/circ/alt_holds_print.js"></script>
<script type="text/javascript">
- dojo.require("dojo.cookie");
- dojo.require("dojox.xml.parser");
- dojo.require("openils.BibTemplate");
- dojo.require("openils.widget.ProgressDialog");
-
- function do_pull_list(user, cgi) {
- progress_dialog.show(true);
-
- var any = false;
-
- fieldmapper.standardRequest(
- ['open-ils.circ','open-ils.circ.hold_pull_list.print.stream'],
- { async : true,
- params: [
- user.authtoken,
- { org_id : cgi.param('o'),
- limit : cgi.param('limit'),
- offset : cgi.param('offset'),
- chunk_size : cgi.param('chunk_size'),
- sort : sort_order
- }
- ],
- onresponse : function (r) {
- any = true;
- dojo.forEach( openils.Util.readResponse(r), function (hold_fm) {
-
- // hashify the hold
- var hold = hold_fm.toHash(true);
- hold.usr = hold_fm.usr().toHash(true);
- hold.usr.card = hold_fm.usr().card().toHash(true);
- hold.current_copy = hold_fm.current_copy().toHash(true);
- hold.current_copy.location = hold_fm.current_copy().location().toHash(true);
- hold.current_copy.call_number = hold_fm.current_copy().call_number().toHash(true);
- hold.current_copy.call_number.record = hold_fm.current_copy().call_number().record().toHash(true);
-
- // clone the template's html
- var tr = dojo.clone(
- dojo.query("tr", dojo.byId('template'))[0]
- );
- dojo.query("td:not([type])", tr).forEach(
- function(td) {
- td.innerHTML =
- dojo.string.substitute(td.innerHTML, hold);
- }
- );
-
- new openils.BibTemplate({
- root : tr,
- xml : dojox.xml.parser.parse(hold.current_copy.call_number.record.marc),
- delay: false
- });
-
- dojo.place(tr, "target");
- });
- },
- oncomplete : function () {
- progress_dialog.hide();
- if (any)
- window.print();
- else
- alert(dojo.byId("no_results").innerHTML);
- }
- }
- );
- }
-
- function place_by_sortkey(node, container) {
- /*Don't use a forEach() or anything like that here. too slow.*/
- var sortkey = dojo.attr(node, "sortkey");
- for (var i = 0; i < container.childNodes.length; i++) {
- var rover = container.childNodes[i];
- if (rover.nodeType != 1) continue;
- if (dojo.attr(rover, "sortkey") > sortkey) {
- dojo.place(node, rover, "before");
- return;
- }
- }
- dojo.place(node, container, "last");
- }
-
- function do_shelf_expired_holds(user, cgi) {
- progress_dialog.show(true);
-
- var any = false;
- var target = dojo.byId("target");
- fieldmapper.standardRequest(
- ["open-ils.circ",
- "open-ils.circ.captured_holds.expired.print.stream"], {
- "async": true,
- "params": [
- user.authtoken, {
- "org_id": cgi.param("o"),
- "limit": cgi.param("limit"),
- "offset": cgi.param("offset"),
- "chunk_size": cgi.param("chunk_size"),
- "sort": sort_order
- }
- ],
- "onresponse": function(r) {
- dojo.forEach(
- openils.Util.readResponse(r),
- function(hold_fields) {
- any = true;
- /* munge this object to make it look like
- the template expects */
- var hold = {
- "usr": {},
- "current_copy": {
- "barcode": hold_fields.barcode,
- "call_number": {
- "label": hold_fields.label,
- "record": {"marc": hold_fields.marc}
- },
- "location": {"name": hold_fields.name}
- }
- };
- if (hold_fields.alias) {
- hold.usr.display_name = hold_fields.alias;
- } else {
- hold.usr.display_name = [
- (hold_fields.family_name ? hold_fields.family_name : ""),
- (hold_fields.first_given_name ? hold_fields.first_given_name : ""),
- (hold_fields.second_given_name ? hold_fields.second_given_name : "")
- ].join(" ");
- }
- ["first_given_name","second_given_name","family_name","alias"].forEach(function(k) {hold.usr[k] = hold_fields[k]; });
-
- // clone the template's html
- var tr = dojo.clone(
- dojo.query("tr", dojo.byId('template'))[0]
- );
- dojo.query("td:not([type])", tr).forEach(
- function(td) {
- td.innerHTML =
- dojo.string.substitute(td.innerHTML, hold);
- }
- );
-
- new openils.BibTemplate({
- "root": tr,
- "xml": dojox.xml.parser.parse(hold.current_copy.call_number.record.marc),
- "delay": false
- });
-
- dojo.attr(
- tr, "sortkey", hold.usr.display_name
- );
- place_by_sortkey(tr, target);
- }
- );
- },
- "oncomplete": function() {
- progress_dialog.hide();
- if (any)
- window.print();
- else
- alert(dojo.byId("no_results").innerHTML);
- }
- }
- );
- }
-
function my_init() {
- var cgi = new CGI();
- var ses = (typeof ses == "function" ? ses() : 0) ||
+ cgi = new CGI();
+ authtoken = (typeof ses == "function" ? ses() : 0) ||
cgi.param("ses") || dojo.cookie("ses");
- var user = new openils.User({"authtoken": ses});
if (cgi.param("do") == "shelf_expired_holds") {
- do_shelf_expired_holds(user, cgi);
+ dojo.byId("clear_holds_launcher").onclick = function() {
+ if (confirm("Are you sure you're ready to clear the expired holds from the shelf?")) { /* XXX i18n */
+ do_clear_holds(cgi);
+ }
+ };
+ openils.Util.show("clear_holds_deck");
} else {
dojo.query("[only='shelf_expired_holds']").forEach(dojo.destroy);
- do_pull_list(user, cgi);
+ do_pull_list(cgi);
}
}
dojo.addOnLoad(my_init);
@@ -225,24 +64,34 @@
</head>
<body class='tundra'>
- <div dojoType="openils.widget.ProgressDialog" jsId="progress_dialog"></div>
+ <div style="width: 320px;"
+ dojoType="openils.widget.ProgressDialog"
+ jsId="progress_dialog"></div>
<div class="hide_me" id="no_results">No results</div>
+ <div class="hide_me" id="clear_holds_deck">
+ [ <a id="clear_holds_launcher"
+ href="javascript:void(0);">Clear expired holds</a> ]
+ <small><em id="clear_holds_set_label"></em></small>
+ </div>
<!-- START OF TEMPLATE SECTION -->
-
<table>
- <tbody id='target'>
+ <thead>
<tr>
<th only="shelf_expired_holds">Patron</th>
+ <th only="shelf_expired_holds">Action</th>
<th>Title</th>
<th>Author</th>
<th>Shelving Location</th>
<th>Call Number</th>
<th>Barcode</th>
</tr>
+ </thead>
+ <tbody id='target'>
</tbody>
<tbody id='template' class='hide_me'>
<tr>
<td only="shelf_expired_holds">${usr.display_name}</td>
+ <td only="shelf_expired_holds">${action}</td>
<td type='opac/slot-data' query='datafield[tag=245]'></td>
<td type='opac/slot-data' query='datafield[tag^=1]' limit='1'> </td>
<td>${current_copy.location.name}</td>
@@ -251,9 +100,6 @@
</tr>
</tbody>
</table>
-
<!-- END OF TEMPLATE SECTION -->
-
-
</body>
</html>
Copied: branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.js (from rev 18230, trunk/Open-ILS/web/opac/extras/circ/alt_holds_print.js)
===================================================================
--- branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.js (rev 0)
+++ branches/rel_2_0/Open-ILS/web/opac/extras/circ/alt_holds_print.js 2010-10-07 22:48:12 UTC (rev 18232)
@@ -0,0 +1,202 @@
+dojo.require("dojo.cookie");
+dojo.require("dojox.xml.parser");
+dojo.require("openils.BibTemplate");
+dojo.require("openils.widget.ProgressDialog");
+
+var authtoken;
+var cgi;
+
+function do_pull_list() {
+ progress_dialog.show(true);
+
+ var any = false;
+
+ fieldmapper.standardRequest(
+ ['open-ils.circ','open-ils.circ.hold_pull_list.print.stream'],
+ { async : true,
+ params: [
+ authtoken, {
+ org_id : cgi.param('o'),
+ limit : cgi.param('limit'),
+ offset : cgi.param('offset'),
+ chunk_size : cgi.param('chunk_size'),
+ sort : sort_order
+ }
+ ],
+ onresponse : function (r) {
+ any = true;
+ dojo.forEach( openils.Util.readResponse(r), function (hold_fm) {
+
+ // hashify the hold
+ var hold = hold_fm.toHash(true);
+ hold.usr = hold_fm.usr().toHash(true);
+ hold.usr.card = hold_fm.usr().card().toHash(true);
+ hold.current_copy = hold_fm.current_copy().toHash(true);
+ hold.current_copy.location = hold_fm.current_copy().location().toHash(true);
+ hold.current_copy.call_number = hold_fm.current_copy().call_number().toHash(true);
+ hold.current_copy.call_number.record = hold_fm.current_copy().call_number().record().toHash(true);
+
+ // clone the template's html
+ var tr = dojo.clone(
+ dojo.query("tr", dojo.byId('template'))[0]
+ );
+ dojo.query("td:not([type])", tr).forEach(
+ function(td) {
+ td.innerHTML =
+ dojo.string.substitute(td.innerHTML, hold);
+ }
+ );
+
+ new openils.BibTemplate({
+ root : tr,
+ xml : dojox.xml.parser.parse(hold.current_copy.call_number.record.marc),
+ delay: false
+ });
+
+ dojo.place(tr, "target");
+ });
+ },
+ oncomplete : function () {
+ progress_dialog.hide();
+ if (any)
+ window.print();
+ else
+ alert(dojo.byId("no_results").innerHTML);
+ }
+ }
+ );
+}
+
+function place_by_sortkey(node, container) {
+ /*Don't use a forEach() or anything like that here. too slow.*/
+ var sortkey = dojo.attr(node, "sortkey");
+ for (var i = 0; i < container.childNodes.length; i++) {
+ var rover = container.childNodes[i];
+ if (rover.nodeType != 1) continue;
+ if (dojo.attr(rover, "sortkey") > sortkey) {
+ dojo.place(node, rover, "before");
+ return;
+ }
+ }
+ dojo.place(node, container, "last");
+}
+
+function hashify_fields(fields) {
+ var hold = {
+ "usr": {},
+ "current_copy": {
+ "barcode": fields.barcode,
+ "call_number": {
+ "label": fields.label,
+ "record": {"marc": fields.marc}
+ },
+ "location": {"name": fields.name}
+ }
+ };
+
+ if (fields.alias) {
+ hold.usr.display_name = fields.alias;
+ } else {
+ hold.usr.display_name = [
+ (fields.family_name ? fields.family_name : ""),
+ (fields.first_given_name ? fields.first_given_name : ""),
+ (fields.second_given_name ? fields.second_given_name : "")
+ ].join(" ");
+ }
+
+ ["first_given_name","second_given_name","family_name","alias"].forEach(
+ function(k) { hold.usr[k] = fields[k]; }
+ );
+
+ return hold;
+}
+
+function do_clear_holds() {
+ progress_dialog.show(true);
+
+ var launcher;
+ fieldmapper.standardRequest(
+ ["open-ils.circ", "open-ils.circ.hold.clear_shelf.process"], {
+ "async": true,
+ "params": [authtoken, cgi.param("o")],
+ "onresponse": function(r) {
+ if (r = openils.Util.readResponse(r)) {
+ if (r.cache_key) { /* complete */
+ launcher = dojo.byId("clear_holds_launcher");
+ launcher.innerHTML = "Re-fetch for Printing"; /* XXX i18n */
+ launcher.onclick =
+ function() { do_clear_holds_from_cache(r.cache_key); };
+ dojo.byId("clear_holds_set_label").innerHTML = r.cache_key;
+ } else if (r.maximum) {
+ progress_dialog.update(r);
+ }
+ }
+ },
+ "oncomplete": function() {
+ progress_dialog.hide();
+ if (launcher) launcher.onclick();
+ else alert(dojo.byId("no_results").innerHTML);
+ }
+ }
+ );
+}
+
+function do_clear_holds_from_cache(cache_key) {
+ progress_dialog.show(true);
+
+ var any = 0;
+ var target = dojo.byId("target");
+ dojo.empty(target);
+ var template = dojo.query("tr", dojo.byId("template"))[0];
+ fieldmapper.standardRequest(
+ ["open-ils.circ",
+ "open-ils.circ.hold.clear_shelf.get_cache"], {
+ "async": true,
+ "params": [authtoken, cache_key, cgi.param("chunk_size")],
+ "onresponse": function(r) {
+ dojo.forEach(
+ openils.Util.readResponse(r),
+ function(resp) {
+ if (resp.maximum) {
+ progress_dialog.update(resp);
+ return;
+ }
+
+ var hold = hashify_fields(resp.hold_details);
+ hold.action = resp.action;
+
+ var tr = dojo.clone(template);
+ any++;
+
+ dojo.query("td:not([type])", tr).forEach(
+ function(td) {
+ td.innerHTML =
+ dojo.string.substitute(td.innerHTML, hold);
+ }
+ );
+
+ new openils.BibTemplate({
+ "root": tr,
+ "xml": dojox.xml.parser.parse(
+ hold.current_copy.call_number.record.marc
+ ),
+ "delay": false
+ });
+
+ dojo.attr(tr, "sortkey", hold.usr.display_name);
+ place_by_sortkey(tr, target);
+ }
+ );
+ progress_dialog.update({"progress": any});
+ },
+ "oncomplete": function() {
+ progress_dialog.hide();
+ if (any)
+ window.print();
+ else
+ alert(dojo.byId("no_results").innerHTML);
+ }
+ }
+ );
+}
+
More information about the open-ils-commits
mailing list