From 9aaf3351dc4f2dbf649ea1c2cb5711fc98637fbb Mon Sep 17 00:00:00 2001 From: Jason Etheridge Date: Wed, 29 Jun 2011 12:12:31 -0400 Subject: [PATCH] Staff UI for batch holds on items. "Request Item" action in Holdings Maintenance, Item Status, and Copy Buckets is the entry-point. Works on selected items in the first two interfaces and all items in the bucket for the latter. UI allows you to place Copy type, Recall type, or Force type holds. It reports the # of successes and breaks down the failures by failure event. You can retry failures (optionally changing some of the request parameters like Pickup Library) or "override" them. Clicking the hyperlink for a set of failures will show the items involved in a new Item Status tab. More technical blurbs from squashed commits: * "open-ils.circ.holds.test_and_create.batch" Takes an argument hash and a list of targets. All the holds created will be identical except for the targets. * retrieve and display Recall and Force holds like Copy holds * give the Item Status UI an inefficient way to handle being passed copy id's (via xulG) in addition to barcodes * wire-up item hold request ui * place hold UI Signed-off-by: Jason Etheridge Signed-off-by: Bill Erickson --- .../perlmods/lib/OpenILS/Application/Circ/Holds.pm | 117 +++++++- Open-ILS/web/opac/locale/en-US/lang.dtd | 21 ++ .../staff_client/chrome/content/main/constants.js | 4 + .../xul/staff_client/server/cat/copy_browser.js | 12 + .../xul/staff_client/server/cat/copy_browser.xul | 3 + .../xul/staff_client/server/cat/copy_buckets.js | 22 ++ .../xul/staff_client/server/cat/copy_buckets.xul | 1 + .../server/cat/copy_buckets_overlay.xul | 1 + Open-ILS/xul/staff_client/server/cat/util.js | 30 +- .../xul/staff_client/server/circ/copy_status.js | 16 ++ .../xul/staff_client/server/circ/copy_status.xul | 14 + .../server/circ/copy_status_overlay.xul | 2 + .../server/locale/en-US/patron.properties | 12 + Open-ILS/xul/staff_client/server/patron/holds.js | 4 + .../xul/staff_client/server/patron/place_hold.js | 320 +++++++++++++++++++++ .../xul/staff_client/server/patron/place_hold.xul | 105 +++++++ 16 files changed, 681 insertions(+), 3 deletions(-) create mode 100644 Open-ILS/xul/staff_client/server/patron/place_hold.js create mode 100644 Open-ILS/xul/staff_client/server/patron/place_hold.xul diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm index 6d47aeb28..651e9b52a 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm @@ -39,6 +39,105 @@ use OpenSRF::Utils::Cache; my $apputils = "OpenILS::Application::AppUtils"; my $U = $apputils; +__PACKAGE__->register_method( + method => "test_and_create_hold_batch", + api_name => "open-ils.circ.holds.test_and_create.batch", + stream => 1, + signature => { + desc => q/This is for batch creating a set of holds where every field is identical except for the targets./, + params => [ + { desc => 'Authentication token', type => 'string' }, + { desc => 'Hash of named parameters. Same as for open-ils.circ.title_hold.is_possible, though the pertinent target field is automatically populated based on the hold_type and the specified list of targets.', type => 'object'}, + { desc => 'Array of target ids', type => 'array' } + ], + return => { + desc => 'Array of hold ID on success, -1 on missing arg, event (or ref to array of events) on error(s)', + }, + } +); + +__PACKAGE__->register_method( + method => "test_and_create_hold_batch", + api_name => "open-ils.circ.holds.test_and_create.batch.override", + stream => 1, + signature => { + desc => '@see open-ils.circ.holds.test_and_create.batch', + } +); + + +sub test_and_create_hold_batch { + my( $self, $conn, $auth, $params, $target_list ) = @_; + + my $override = 1 if $self->api_name =~ /override/; + + my $e = new_editor(authtoken=>$auth); + return $e->die_event unless $e->checkauth; + $$params{'requestor'} = $e->requestor->id; + + my $target_field; + if ($$params{'hold_type'} eq 'T') { $target_field = 'titleid'; } + elsif ($$params{'hold_type'} eq 'C') { $target_field = 'copy_id'; } + elsif ($$params{'hold_type'} eq 'R') { $target_field = 'copy_id'; } + elsif ($$params{'hold_type'} eq 'F') { $target_field = 'copy_id'; } + elsif ($$params{'hold_type'} eq 'I') { $target_field = 'issuanceid'; } + elsif ($$params{'hold_type'} eq 'V') { $target_field = 'volume_id'; } + elsif ($$params{'hold_type'} eq 'M') { $target_field = 'mrid'; } + elsif ($$params{'hold_type'} eq 'P') { $target_field = 'partid'; } + else { return undef; } + + foreach (@$target_list) { + $$params{$target_field} = $_; + my $res; + if (! $override) { + ($res) = $self->method_lookup( + 'open-ils.circ.title_hold.is_possible')->run($auth, $params); + } + if ($override || $res->{'success'} == 1) { + my $ahr = construct_hold_request_object($params); + my ($res2) = $self->method_lookup( + $override + ? 'open-ils.circ.holds.create.override' + : 'open-ils.circ.holds.create' + )->run($auth, $ahr); + $res2 = { + 'target' => $$params{$target_field}, + 'result' => $res2 + }; + $conn->respond($res2); + } else { + $res = { + 'target' => $$params{$target_field}, + 'result' => $res + }; + $conn->respond($res); + } + } + return undef; +} + +sub construct_hold_request_object { + my ($params) = @_; + + my $ahr = Fieldmapper::action::hold_request->new; + $ahr->isnew('1'); + + foreach my $field (keys %{ $params }) { + if ($field eq 'depth') { $ahr->selection_depth($$params{$field}); } + elsif ($field eq 'patronid') { + $ahr->usr($$params{$field}); } + elsif ($field eq 'titleid') { $ahr->target($$params{$field}); } + elsif ($field eq 'copy_id') { $ahr->target($$params{$field}); } + elsif ($field eq 'issuanceid') { $ahr->target($$params{$field}); } + elsif ($field eq 'volume_id') { $ahr->target($$params{$field}); } + elsif ($field eq 'mrid') { $ahr->target($$params{$field}); } + elsif ($field eq 'partid') { $ahr->target($$params{$field}); } + else { + $ahr->$field($$params{$field}); + } + } + return $ahr; +} __PACKAGE__->register_method( method => "create_hold_batch", @@ -2750,7 +2849,7 @@ sub all_rec_holds { $args->{fulfillment_time} = undef; # we don't want to see old fulfilled holds $args->{cancel_time} = undef; - my $resp = { volume_holds => [], copy_holds => [], metarecord_holds => [], part_holds => [], issuance_holds => [] }; + my $resp = { volume_holds => [], copy_holds => [], recall_holds => [], force_holds => [], metarecord_holds => [], part_holds => [], issuance_holds => [] }; my $mr_map = $e->search_metabib_metarecord_source_map({source => $title_id})->[0]; if($mr_map) { @@ -2826,6 +2925,20 @@ sub all_rec_holds { %$args }, {idlist=>1} ); + $resp->{recall_holds} = $e->search_action_hold_request( + { + hold_type => OILS_HOLD_TYPE_RECALL, + target => $copies, + %$args }, + {idlist=>1} ); + + $resp->{force_holds} = $e->search_action_hold_request( + { + hold_type => OILS_HOLD_TYPE_FORCE, + target => $copies, + %$args }, + {idlist=>1} ); + return $resp; } @@ -2965,7 +3078,7 @@ sub find_hold_mvr { $tid = $part->record; - } elsif( $hold->hold_type eq OILS_HOLD_TYPE_COPY ) { + } elsif( $hold->hold_type eq OILS_HOLD_TYPE_COPY || $hold->hold_type eq OILS_HOLD_TYPE_RECALL || $hold->hold_type eq OILS_HOLD_TYPE_FORCE ) { $copy = $e->retrieve_asset_copy([ $hold->target, {flesh => 1, flesh_fields => {acp => ['call_number']}} diff --git a/Open-ILS/web/opac/locale/en-US/lang.dtd b/Open-ILS/web/opac/locale/en-US/lang.dtd index ffbce223a..6b90ecd95 100644 --- a/Open-ILS/web/opac/locale/en-US/lang.dtd +++ b/Open-ILS/web/opac/locale/en-US/lang.dtd @@ -2285,6 +2285,8 @@ + + @@ -2553,6 +2555,8 @@ + + @@ -2639,6 +2643,8 @@ + + @@ -3582,3 +3588,18 @@ + + + + + + + + + + + + + + + diff --git a/Open-ILS/xul/staff_client/chrome/content/main/constants.js b/Open-ILS/xul/staff_client/chrome/content/main/constants.js index d02c17224..4d61b10de 100644 --- a/Open-ILS/xul/staff_client/chrome/content/main/constants.js +++ b/Open-ILS/xul/staff_client/chrome/content/main/constants.js @@ -100,6 +100,7 @@ var api = { 'FM_ACP_RETRIEVE_VIA_BARCODE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed2.find_by_barcode', 'secure' : false }, 'FM_ACP_RETRIEVE_VIA_BARCODE.authoritative' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed2.find_by_barcode.authoritative', 'secure' : false }, 'FM_ACP_FLESHED_BATCH_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed.batch.retrieve', 'secure' : false }, + 'FM_ACP_UNFLESHED_BATCH_RETRIEVE' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.batch.retrieve', 'secure' : false }, 'FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.asset.copy.fleshed.batch.retrieve.authoritative', 'secure' : false }, 'FM_ACP_FLESHED_BATCH_UPDATE' : { 'app' : 'open-ils.cat', 'method' : 'open-ils.cat.asset.copy.fleshed.batch.update' }, 'FM_ACP_COUNT' : { 'app' : 'open-ils.search', 'method' : 'open-ils.search.biblio.record.copy_count.staff', 'secure' : false }, @@ -117,6 +118,8 @@ var api = { 'FM_AHN_CREATE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_notification.create' }, 'FM_AHN_RETRIEVE_VIA_AHR' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_notification.retrieve_by_hold' }, 'FM_AHN_RETRIEVE_VIA_AHR.authoritative' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold_notification.retrieve_by_hold.authoritative' }, + 'FM_AHR_CHECK_AND_CREATE.batch' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.holds.test_and_create.batch' }, + 'FM_AHR_CHECK_AND_CREATE.batch.override' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.holds.test_and_create.batch.override' }, 'FM_AHR_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.holds.retrieve_by_id' }, 'FM_AHR_BLOB_RETRIEVE' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold.details.retrieve' }, 'FM_AHR_BLOB_RETRIEVE.authoritative' : { 'app' : 'open-ils.circ', 'method' : 'open-ils.circ.hold.details.retrieve.authoritative' }, @@ -416,6 +419,7 @@ var urls = { 'XUL_HOLDS_BROWSER' : '/xul/server/patron/holds.xul', 'XUL_HOLD_DETAILS' : '/xul/server/patron/hold_details.xul', 'XUL_HOLD_CANCEL' : '/xul/server/patron/hold_cancel.xul', + 'XUL_HOLD_PLACEMENT' : '/xul/server/patron/place_hold.xul', 'XUL_IN_HOUSE_USE' : '/xul/server/circ/in_house_use.xul', 'XUL_LIST_CLIPBOARD' : '/xul/server/util/list_clipboard.xul', 'XUL_LOCAL_ADMIN' : '/xul/server/admin/index.xhtml', diff --git a/Open-ILS/xul/staff_client/server/cat/copy_browser.js b/Open-ILS/xul/staff_client/server/cat/copy_browser.js index 912265580..2269e30de 100644 --- a/Open-ILS/xul/staff_client/server/cat/copy_browser.js +++ b/Open-ILS/xul/staff_client/server/cat/copy_browser.js @@ -111,6 +111,18 @@ cat.copy_browser.prototype = { obj.list.clear(); } ], + 'cmd_request_items' : [ + ['command'], + function() { + JSAN.use('cat.util'); JSAN.use('util.functional'); + + var list = util.functional.filter_list( obj.sel_list, function (o) { return o.split(/_/)[0] == 'acp'; }); + + list = util.functional.map_list( list, function (o) { return o.split(/_/)[1]; }); + + cat.util.request_items( list ); + } + ], 'sel_mark_items_damaged' : [ ['command'], function() { diff --git a/Open-ILS/xul/staff_client/server/cat/copy_browser.xul b/Open-ILS/xul/staff_client/server/cat/copy_browser.xul index d161d121f..79028aa95 100644 --- a/Open-ILS/xul/staff_client/server/cat/copy_browser.xul +++ b/Open-ILS/xul/staff_client/server/cat/copy_browser.xul @@ -81,6 +81,7 @@ vim:noet:sw=4:ts=4: + @@ -126,6 +127,7 @@ vim:noet:sw=4:ts=4: + @@ -181,6 +183,7 @@ vim:noet:sw=4:ts=4: + diff --git a/Open-ILS/xul/staff_client/server/cat/copy_buckets.js b/Open-ILS/xul/staff_client/server/cat/copy_buckets.js index d9abdfbd2..cc7b5a9e8 100644 --- a/Open-ILS/xul/staff_client/server/cat/copy_buckets.js +++ b/Open-ILS/xul/staff_client/server/cat/copy_buckets.js @@ -533,6 +533,28 @@ cat.copy_buckets.prototype = { } ], + 'cmd_request_items' : [ + ['command'], + function() { + try { + obj.list2.select_all(); + + var copy_ids = util.functional.map_list( + obj.list2.dump_retrieve_ids(), + function (o) { + return JSON2js(o)[0]; // acp_id + } + ) + + JSAN.use('cat.util'); + cat.util.request_items(copy_ids); + + } catch(E) { + obj.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_buckets.copy_buckets_transfer_to_volume.error'), E); + } + } + ], + 'copy_buckets_transfer_to_volume' : [ ['command'], function() { diff --git a/Open-ILS/xul/staff_client/server/cat/copy_buckets.xul b/Open-ILS/xul/staff_client/server/cat/copy_buckets.xul index ac6b9f608..90f2d1959 100644 --- a/Open-ILS/xul/staff_client/server/cat/copy_buckets.xul +++ b/Open-ILS/xul/staff_client/server/cat/copy_buckets.xul @@ -88,6 +88,7 @@ + diff --git a/Open-ILS/xul/staff_client/server/cat/copy_buckets_overlay.xul b/Open-ILS/xul/staff_client/server/cat/copy_buckets_overlay.xul index 192c49d26..57016047b 100644 --- a/Open-ILS/xul/staff_client/server/cat/copy_buckets_overlay.xul +++ b/Open-ILS/xul/staff_client/server/cat/copy_buckets_overlay.xul @@ -73,6 +73,7 @@