From: Jason Etheridge Date: Wed, 29 Jun 2011 16:12:31 +0000 (-0400) Subject: Staff UI for batch holds on items. X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=9aaf3351dc4f2dbf649ea1c2cb5711fc98637fbb;p=evergreen%2Fpines.git 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 --- 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 6d47aeb281..651e9b52ad 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 ffbce223ae..6b90ecd95c 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 d02c17224f..4d61b10dec 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 9122655808..2269e30de1 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 d161d121f5..79028aa95e 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 d9abdfbd21..cc7b5a9e80 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 ac6b9f6089..90f2d19590 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 192c49d268..57016047be 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 @@