[open-ils-commits] [GIT] Evergreen ILS branch master updated. 9aaf3351dc4f2dbf649ea1c2cb5711fc98637fbb

Evergreen Git git at git.evergreen-ils.org
Thu Jun 30 11:10:16 EDT 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  9aaf3351dc4f2dbf649ea1c2cb5711fc98637fbb (commit)
      from  08c539bc8cad0cd19f109ccd6be411b0335dff65 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 9aaf3351dc4f2dbf649ea1c2cb5711fc98637fbb
Author: Jason Etheridge <jason at esilibrary.com>
Date:   Wed Jun 29 12:12:31 2011 -0400

    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 <jason at esilibrary.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

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 6d47aeb..651e9b5 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 ffbce22..6b90ecd 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 @@
 <!ENTITY staff.circ.copy_status_overlay.cmd_triggered_events.accesskey "T">
 <!ENTITY staff.circ.copy_status_overlay.cmd_book_item_now.label "Book Item Now">
 <!ENTITY staff.circ.copy_status_overlay.cmd_book_item_now.accesskey "N">
+<!ENTITY staff.circ.copy_status_overlay.cmd_request_items.label "Request Item">
+<!ENTITY staff.circ.copy_status_overlay.cmd_request_items.accesskey "R">
 <!ENTITY staff.circ.copy_status_overlay.cmd_create_brt.label "Make Item Bookable">
 <!ENTITY staff.circ.copy_status_overlay.cmd_create_brt.accesskey "K">
 <!ENTITY staff.circ.copy_status_overlay.cmd_find_acq_po.label "Find Originating Acquisition">
@@ -2553,6 +2555,8 @@
 <!ENTITY staff.cat.copy_browser.actions.cmd_transfer_volume.accesskey "T">
 <!ENTITY staff.cat.copy_browser.actions.cmd_delete_items.label "Delete Items">
 <!ENTITY staff.cat.copy_browser.actions.cmd_delete_volumes.label "Delete Volumes">
+<!ENTITY staff.cat.copy_browser.actions.cmd_request_items.label "Request Item">
+<!ENTITY staff.cat.copy_browser.actions.cmd_request_items.accesskey "R">
 <!ENTITY staff.cat.copy_browser.actions.sel_mark_items_damaged.label "Mark Item Damaged">
 <!ENTITY staff.cat.copy_browser.actions.sel_mark_items_damaged.accesskey "D">
 <!ENTITY staff.cat.copy_browser.actions.sel_mark_items_missing.label "Mark Item Missing">
@@ -2639,6 +2643,8 @@
 <!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.cmd_copy_buckets_export.label "Export">
 <!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.batch.label "Batch:">
 <!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.cmd_export_to_copy_status.label "Show Status">
+<!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.cmd_request_items.label "Request Items">
+<!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.cmd_request_items.accesskey "R">
 <!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.copy_buckets_transfer_to_volume.label "Transfer to Specific Volume">
 <!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.copy_buckets_batch_copy_edit.label "Edit Item Attributes">
 <!ENTITY staff.cat.copy_buckets_overlay.copy_buckets.copy_buckets_batch_copy_delete.label "Delete All from Catalog">
@@ -3582,3 +3588,18 @@
 <!ENTITY staff.client.portal.receipts "Edit Receipt Templates">
 <!ENTITY staff.client.portal.copyright "Copyright &copy; 2006-2011 Georgia Public Library Service, and others">
 <!ENTITY staff.client.portal.poweredby "Powered by">
+<!ENTITY staff.item.batch.hold.groupbox_caption "Request Details">
+<!ENTITY staff.item.batch.hold.hold_type_menu.label "Hold Type">
+<!ENTITY staff.item.batch.hold.hold_type_menu.accesskey "T">
+<!ENTITY staff.item.batch.hold.hold_type_menuentry.copy_hold "Copy Hold">
+<!ENTITY staff.item.batch.hold.hold_type_menuentry.recall_hold "Recall Hold">
+<!ENTITY staff.item.batch.hold.hold_type_menuentry.force_hold "Force Hold">
+<!ENTITY staff.item.batch.hold.pick_up_lib_menu.label "Pickup Library">
+<!ENTITY staff.item.batch.hold.pick_up_lib_menu.accesskey "P">
+<!ENTITY staff.item.batch.hold.hold_usr.label "Hold User Barcode">
+<!ENTITY staff.item.batch.hold.hold_usr.accesskey "U">
+<!ENTITY staff.item.batch.hold.request_btn.label "Make Request">
+<!ENTITY staff.item.batch.hold.request_btn.accesskey "M">
+<!ENTITY staff.item.batch.hold.cancel_btn.label "Cancel">
+<!ENTITY staff.item.batch.hold.cancel_btn.accesskey "C">
+<!ENTITY staff.item.batch.hold.failures_and_settings "The settings above may be changed for retries and overrides.">
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 d02c172..4d61b10 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 9122655..2269e30 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 d161d12..79028aa 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:
         <command id="cmd_show_all_libs" />
         <command id="cmd_show_libs_with_copies" />
 
+        <command id="cmd_request_items" />
         <command id="sel_mark_items_damaged" />
         <command id="sel_mark_items_missing" />
         <command id="cmd_add_items"/>
@@ -126,6 +127,7 @@ vim:noet:sw=4:ts=4:
             <menuitem command="cmd_delete_items" label="&staff.cat.copy_browser.actions.cmd_delete_items.label;" accesskey=""/>
             <menuitem command="cmd_delete_volumes" label="&staff.cat.copy_browser.actions.cmd_delete_volumes.label;" accesskey=""/>
             <menuseparator/>
+            <menuitem command="cmd_request_items" label="&staff.cat.copy_browser.actions.cmd_request_items.label;" accesskey="&staff.cat.copy_browser.actions.cmd_request_items.accesskey;"/>
             <menuitem command="sel_mark_items_damaged" label="&staff.cat.copy_browser.actions.sel_mark_items_damaged.label;" accesskey="&staff.cat.copy_browser.actions.sel_mark_items_damaged.accesskey;"/>
             <menuitem command="sel_mark_items_missing" label="&staff.cat.copy_browser.actions.sel_mark_items_missing.label;" accesskey="&staff.cat.copy_browser.actions.sel_mark_items_missing.accesskey;"/>
             <menuseparator/>
@@ -181,6 +183,7 @@ vim:noet:sw=4:ts=4:
                         <menuitem command="cmd_delete_items" label="&staff.cat.copy_browser.holdings_maintenance.cmd_delete_items.label;" accesskey=""/>
                         <menuitem command="cmd_delete_volumes" label="&staff.cat.copy_browser.holdings_maintenance.cmd_delete_volumes.label;" accesskey=""/>
                         <menuseparator/>
+                        <menuitem command="cmd_request_items" label="&staff.cat.copy_browser.actions.cmd_request_items.label;" accesskey="&staff.cat.copy_browser.actions.cmd_request_items.accesskey;"/>
                         <menuitem command="sel_mark_items_damaged" label="&staff.cat.copy_browser.holdings_maintenance.sel_mark_items_damaged.label;" accesskey="&staff.cat.copy_browser.holdings_maintenance.sel_mark_items_damaged.accesskey;"/>
                         <menuitem command="sel_mark_items_missing" label="&staff.cat.copy_browser.holdings_maintenance.sel_mark_items_missing.label;" accesskey="&staff.cat.copy_browser.holdings_maintenance.sel_mark_items_missing.accesskey;"/>
                         <menuseparator/>
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 d9abdfb..cc7b5a9 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 ac6b9f6..90f2d19 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 @@
         <command id="copy_buckets_transfer_to_volume" />
         <command id="copy_buckets_batch_copy_edit" />
         <command id="copy_buckets_batch_copy_delete" />
+        <command id="cmd_request_items" />
     </commandset>
 
     <box id="copy_buckets_main" />
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 192c49d..5701604 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 @@
     <hbox style="background: grey">
         <vbox><spacer flex="1"/><label value="&staff.cat.copy_buckets_overlay.copy_buckets.batch.label;" style="font-weight: bold"/><spacer flex="1"/></vbox>
         <button label="&staff.cat.copy_buckets_overlay.copy_buckets.cmd_export_to_copy_status.label;" command="cmd_export_to_copy_status"/>
+        <button command="cmd_request_items" label="&staff.cat.copy_buckets_overlay.copy_buckets.cmd_request_items.label;" accesskey="&staff.cat.copy_buckets_overlay.copy_buckets.cmd_request_items.accesskey;"/>
         <button command="copy_buckets_transfer_to_volume" label="&staff.cat.copy_buckets_overlay.copy_buckets.copy_buckets_transfer_to_volume.label;"/>
         <button command="copy_buckets_batch_copy_edit" label="&staff.cat.copy_buckets_overlay.copy_buckets.copy_buckets_batch_copy_edit.label;" image="/xul/server/skin/media/images/grinder.gif"/>
         <button command="copy_buckets_batch_copy_delete" label="&staff.cat.copy_buckets_overlay.copy_buckets.copy_buckets_batch_copy_delete.label;" />
diff --git a/Open-ILS/xul/staff_client/server/cat/util.js b/Open-ILS/xul/staff_client/server/cat/util.js
index 64358a4..19ee2ab 100644
--- a/Open-ILS/xul/staff_client/server/cat/util.js
+++ b/Open-ILS/xul/staff_client/server/cat/util.js
@@ -11,7 +11,8 @@ cat.util.EXPORT_OK    = [
     'make_bookable', 'edit_new_brsrc', 'edit_new_bresv', 'batch_edit_volumes', 'render_fine_level',
     'render_loan_duration', 'mark_item_as_missing_pieces', 'render_callnumbers_for_bib_menu',
     'render_cn_prefix_menuitems', 'render_cn_suffix_menuitems', 'render_cn_class_menu',
-    'render_cn_prefix_menu', 'render_cn_suffix_menu', 'transfer_specific_title_holds'
+    'render_cn_prefix_menu', 'render_cn_suffix_menu', 'transfer_specific_title_holds',
+    'request_items'
 ];
 cat.util.EXPORT_TAGS    = { ':all' : cat.util.EXPORT_OK };
 
@@ -1118,4 +1119,31 @@ cat.util.render_cn_suffix_menu = function(ou_ids,extra_menuitems,menu_default) {
     }
 }
 
+cat.util.request_items = function(copy_ids) {
+    var error;
+    try {
+        JSAN.use('util.error');
+        error = new util.error();
+
+        JSAN.use('util.functional');
+        if (!copy_ids) { return; }
+        copy_ids = util.functional.filter_list(
+            copy_ids,
+            function(o) { return o != null; }
+        );
+        if (copy_ids.length < 1) { return; }
+
+        xulG.new_tab(
+            urls.XUL_HOLD_PLACEMENT,
+            {},
+            {
+                'copy_ids' : copy_ids
+            }
+        );
+
+    } catch(E) {
+        alert('Error in cat.util.request_items: ' + E);
+    }
+}
+
 dump('exiting cat/util.js\n');
diff --git a/Open-ILS/xul/staff_client/server/circ/copy_status.js b/Open-ILS/xul/staff_client/server/circ/copy_status.js
index f2816c1..bfd7b79 100644
--- a/Open-ILS/xul/staff_client/server/circ/copy_status.js
+++ b/Open-ILS/xul/staff_client/server/circ/copy_status.js
@@ -67,6 +67,7 @@ circ.copy_status.prototype = {
                             obj.controller.view.cmd_triggered_events.setAttribute('disabled','true');
                             obj.controller.view.cmd_create_brt.setAttribute('disabled','true');
                             obj.controller.view.cmd_book_item_now.setAttribute('disabled','true');
+                            obj.controller.view.cmd_request_items.setAttribute('disabled','true');
                             obj.controller.view.cmd_find_acq_po.setAttribute('disabled','true');
                             obj.controller.view.sel_spine.setAttribute('disabled','true');
                             obj.controller.view.sel_transit_abort.setAttribute('disabled','true');
@@ -98,6 +99,7 @@ circ.copy_status.prototype = {
                             } else {
                                 obj.controller.view.cmd_book_item_now.setAttribute('disabled','true');
                             }
+                            obj.controller.view.cmd_request_items.setAttribute('disabled','false');
                             obj.controller.view.cmd_create_brt.setAttribute('disabled','false');
                             obj.controller.view.cmd_find_acq_po.setAttribute("disabled", obj.selection_list.length == 1 ? "false" : "true");
                             obj.controller.view.sel_spine.setAttribute('disabled','false');
@@ -232,6 +234,20 @@ circ.copy_status.prototype = {
                             }
                         }
                     ],
+                    'cmd_request_items' : [
+                        ['command'],
+                        function() {
+                            JSAN.use('cat.util'); JSAN.use('util.functional');
+
+                            var list = util.functional.map_list(
+                                obj.selection_list, function (o) {
+                                    return o.copy_id;
+                                }
+                            );
+
+                            cat.util.request_items( list );
+                        }
+                    ],
                     "cmd_find_acq_po" : [
                         ["command"],
                         function() {
diff --git a/Open-ILS/xul/staff_client/server/circ/copy_status.xul b/Open-ILS/xul/staff_client/server/circ/copy_status.xul
index 6cee443..6a1411a 100644
--- a/Open-ILS/xul/staff_client/server/circ/copy_status.xul
+++ b/Open-ILS/xul/staff_client/server/circ/copy_status.xul
@@ -72,6 +72,19 @@
                         }
                     ) || [];
                 }
+                if (xulG.copy_ids) {
+                    JSAN.use('util.functional');
+                    JSAN.use('util.network');
+                    var net = new util.network();
+                    g.barcodes = g.barcodes.concat(
+                        util.functional.map_list(
+                            net.simple_request('FM_ACP_UNFLESHED_BATCH_RETRIEVE',[xulG.copy_ids]),
+                            function(o) {
+                                return o.barcode();
+                            }
+                        )
+                    );
+                }
 
                 window.xulG.fetched_copy_details = {};
 
@@ -117,6 +130,7 @@
         <command id="cmd_find_acq_po" disabled="true"/>
         <command id="cmd_create_brt" disabled="true"/>
         <command id="cmd_book_item_now" disabled="true"/>
+        <command id="cmd_request_items" disabled="true"/>
         <command id="sel_copy_details" disabled="true"/>
         <command id="sel_mark_items_damaged" disabled="true"/>
         <command id="sel_mark_items_missing" disabled="true"/>
diff --git a/Open-ILS/xul/staff_client/server/circ/copy_status_overlay.xul b/Open-ILS/xul/staff_client/server/circ/copy_status_overlay.xul
index 770400a..d8ffd77 100644
--- a/Open-ILS/xul/staff_client/server/circ/copy_status_overlay.xul
+++ b/Open-ILS/xul/staff_client/server/circ/copy_status_overlay.xul
@@ -20,6 +20,7 @@
         <menuseparator/>
         <menuitem command="cmd_create_brt" label="&staff.circ.copy_status_overlay.cmd_create_brt.label;" accesskey="&staff.circ.copy_status_overlay.cmd_create_brt.accesskey;"/>
         <menuitem command="cmd_book_item_now" label="&staff.circ.copy_status_overlay.cmd_book_item_now.label;" accesskey="&staff.circ.copy_status_overlay.cmd_book_item_now.accesskey;"/>
+        <menuitem command="cmd_request_items" label="&staff.circ.copy_status_overlay.cmd_request_items.label;" accesskey="&staff.circ.copy_status_overlay.cmd_request_items.accesskey;"/>
         <menuseparator/>
         <menuitem command="cmd_find_acq_po" label="&staff.circ.copy_status_overlay.cmd_find_acq_po.label;" accesskey="&staff.circ.copy_status_overlay.cmd_find_acq_po.accesskey;"/>
         <menuseparator/>
@@ -161,6 +162,7 @@
             <menuseparator />
             <menuitem command="cmd_create_brt" label="&staff.circ.copy_status_overlay.cmd_create_brt.label;" accesskey="&staff.circ.copy_status_overlay.cmd_create_brt.accesskey;"/>
             <menuitem command="cmd_book_item_now" label="&staff.circ.copy_status_overlay.cmd_book_item_now.label;" accesskey="&staff.circ.copy_status_overlay.cmd_book_item_now.accesskey;"/>
+            <menuitem command="cmd_request_items" label="&staff.circ.copy_status_overlay.cmd_request_items.label;" accesskey="&staff.circ.copy_status_overlay.cmd_request_items.accesskey;"/>
             <menuseparator />
             <menuitem command="cmd_find_acq_po" label="&staff.circ.copy_status_overlay.cmd_find_acq_po.label;" accesskey="&staff.circ.copy_status_overlay.cmd_find_acq_po.accesskey;"/>
             <menuseparator/>
diff --git a/Open-ILS/xul/staff_client/server/locale/en-US/patron.properties b/Open-ILS/xul/staff_client/server/locale/en-US/patron.properties
index ba789c8..9bbb2cc 100644
--- a/Open-ILS/xul/staff_client/server/locale/en-US/patron.properties
+++ b/Open-ILS/xul/staff_client/server/locale/en-US/patron.properties
@@ -398,3 +398,15 @@ web.staff.patron.ue.uedit_show_addr_replacement=<div>Replaces address <b>%1$s</b
 
 # 1 - Staff Username  2 - Patron Family  3 - Patron Barcode
 staff.circ.work_log_patron_edit.message=%1$s edited %3$s (%2$s)
+
+# 1 - Number of hold requests created
+staff.item.batch.hold.x_holds_created=%1$s holds created.
+
+# 1 - Number of holds not created for a given reason  2 - the reason for failure
+staff.item.batch.hold.x_failed_holds=%1$s failed for %2$s
+
+staff.item.batch.hold.tab_name=Item Hold/Recall/Force
+staff.item.batch.hold.retry_btn_label=Retry
+staff.item.batch.hold.override_btn_label=Override
+staff.item.batch.hold.user_not_found=User Not Found
+
diff --git a/Open-ILS/xul/staff_client/server/patron/holds.js b/Open-ILS/xul/staff_client/server/patron/holds.js
index c486009..234b2b6 100644
--- a/Open-ILS/xul/staff_client/server/patron/holds.js
+++ b/Open-ILS/xul/staff_client/server/patron/holds.js
@@ -1163,6 +1163,8 @@ patron.holds.prototype = {
                                             opac_url = xulG.url_prefix( urls.opac_rdetail) + '?r=' + my_acn.record();
                                         break;
                                         case 'C' :
+                                        case 'R' :
+                                        case 'F' :
                                             var my_acp = obj.network.simple_request( 'FM_ACP_RETRIEVE', [ htarget ]);
                                             var my_acn;
                                             if (typeof my_acp.call_number() == 'object') {
@@ -1539,6 +1541,8 @@ patron.holds.prototype = {
                 holds = [];
                 if (robj != null) {
                     holds = holds.concat( robj.copy_holds );
+                    holds = holds.concat( robj.recall_holds );
+                    holds = holds.concat( robj.force_holds );
                     holds = holds.concat( robj.volume_holds );
                     holds = holds.concat( robj.title_holds );
                     holds = holds.concat( robj.part_holds );
diff --git a/Open-ILS/xul/staff_client/server/patron/place_hold.js b/Open-ILS/xul/staff_client/server/patron/place_hold.js
new file mode 100644
index 0000000..4c57453
--- /dev/null
+++ b/Open-ILS/xul/staff_client/server/patron/place_hold.js
@@ -0,0 +1,320 @@
+var error;
+var data;
+var net;
+var hold_usr;
+
+function my_init() {
+    try {
+        ui_setup(); // JSAN, tab name, etc.
+        error.sdump('D_TRACE','my_init() for place_hold.xul');
+
+        JSAN.use('OpenILS.data');
+        data = new OpenILS.data();
+        data.stash_retrieve();
+
+        JSAN.use('util.network');
+        net = new util.network();
+
+        var copy_ids = xul_param('copy_ids');
+
+        populate_hold_usr_textbox();
+        populate_pickup_lib_menu();
+
+        $('request_btn').addEventListener(
+            'command',
+            function(ev) {
+                make_request(copy_ids,false);
+            },
+            false
+        );
+        
+        set_remaining_event_listeners();
+
+    } catch(E) {
+        alert('Error in place_hold.js, my_init(): ' + E);
+    }
+}
+
+function make_request(copy_ids,override) {
+    try {
+
+        if (!hold_usr) {
+            alert( $('patronStrings').getString('staff.item.batch.hold.user_not_found') );
+            return;
+        }
+
+        var args = {
+            'hold_type' : $('hold_type_menu').value,
+            'patronid' : hold_usr,
+            'depth' : 0, 
+            'pickup_lib' : $('pickup_lib_menu').value
+        };
+
+        oils_lock_page();
+        $('progress_meter').hidden = false;
+        $('request_btn').disabled = true;
+        $('cancel_btn').disabled = true;
+
+        net.simple_request(
+            override
+            ? 'FM_AHR_CHECK_AND_CREATE.batch.override'
+            : 'FM_AHR_CHECK_AND_CREATE.batch',
+            [ ses(), args, copy_ids ],
+            handle_results
+        );
+
+    } catch(E) {
+        alert('Error in place_hold.js, make_request(): ' + E);
+    }
+}
+
+function handle_results(req) {
+    try {
+        oils_unlock_page();
+        $('progress_meter').hidden = true;
+
+        var results = req.getResultObject();
+
+        var successes = [];
+        var failures = {};
+        var failed_targets = [];
+        var failure_count = 0;
+
+        for (var i = 0; i < results.length; i++) {
+            var payload = results[i];
+            var target = payload.target;
+            var result = payload.result;
+            if (typeof result.length != 'undefined') {
+                // Array; grab first exception for simplicity
+                result = result[0];
+            }
+
+            if (typeof result == 'string' || typeof result == 'number') {
+                successes.push( result ); // hold id's
+            } else {
+                failure_count++;
+                if (typeof failures[ result.textcode ] == 'undefined') {
+                    failures[ result.textcode ] = [];
+                }
+                failures[ result.textcode ].push( target );
+                failed_targets.push( target );
+            }
+        }
+
+        var msg = document.createElement('description');
+        msg.appendChild(
+            document.createTextNode(
+                $('patronStrings').getFormattedString('staff.item.batch.hold.x_holds_created',[ successes.length ])
+            )
+        );
+        $('msgs').appendChild(msg);
+
+        if (failure_count>0) {
+            $('desc').hidden = false;
+            handle_failures(failures,failed_targets);
+        }
+    } catch(E) {
+        alert('Error in place_hold.js, handle_results(): ' + E);
+    }
+}
+
+function handle_failures(failures,failed_targets) {
+    try {
+        for (k in failures) {
+            var err_box = document.createElement('hbox');
+            var err_msg = document.createElement('description');
+            err_box.appendChild(err_msg);
+            $('msgs').appendChild(err_box);
+            err_msg.appendChild(
+                document.createTextNode(
+                    $('patronStrings').getFormattedString('staff.item.batch.hold.x_failed_holds',[ failures[k].length, k ])
+                )
+            );
+            addCSSClass(err_msg,'click_link');
+            err_msg.addEventListener(
+                'click',
+                function(copy_ids) {
+                    return function(ev) {
+                        xulG.new_tab(
+                            urls.XUL_COPY_STATUS,
+                            {},
+                            {
+                                'copy_ids' : copy_ids
+                            }
+                        );
+                    }
+                }(failures[k]),
+                false
+            );
+            var retry_btn = document.createElement('button');
+            retry_btn.setAttribute(
+                'label',
+                $('patronStrings').getString('staff.item.batch.hold.retry_btn_label')
+            );
+            err_box.appendChild(retry_btn);
+
+            retry_btn.addEventListener(
+                'command',
+                function(copy_ids) {
+                    return function(ev) {
+                        ev.target.disabled = true;
+                        ev.target.hidden = true;
+                        ev.target.nextSibling.disabled = true;
+                        ev.target.nextSibling.hidden = true;
+                        make_request(copy_ids,false);
+                    }
+                }(failures[k]),
+                false
+            );
+
+            var override_btn = document.createElement('button');
+            override_btn.setAttribute(
+                'label',
+                $('patronStrings').getString('staff.item.batch.hold.override_btn_label')
+            );
+            err_box.appendChild(override_btn);
+
+            override_btn.addEventListener(
+                'command',
+                function(copy_ids) {
+                    return function(ev) {
+                        ev.target.disabled = true;
+                        ev.target.hidden = true;
+                        ev.target.previousSibling.disabled = true;
+                        ev.target.previousSibling.hidden = true;
+                        make_request(copy_ids,true);
+                    }
+                }(failures[k]),
+                false
+            );
+
+        }
+    } catch(E) {
+        alert('Error in place_hold.js, handle_failures(): ' + E);
+    }
+}
+
+function set_remaining_event_listeners() {
+    try {
+
+        $('hold_type_menu').addEventListener(
+            'command',
+            function(ev) { oils_lock_page(); },
+            false
+        );
+
+        $('cancel_btn').addEventListener(
+            'command',
+            function(ev) { xulG.close_tab(); },
+            false
+        );
+
+    } catch(E) {
+        alert('Error in place_hold.js, set_remaining_event_listeners(): ' + E);
+    } 
+}
+
+function populate_hold_usr_textbox() {
+    JSAN.use('patron.util');
+    hold_usr = ses('staff_id');
+    var au_obj = patron.util.retrieve_fleshed_au_via_id(
+        ses(),
+        hold_usr,
+        ["card"]);
+    $('hold_usr_textbox').value = au_obj.card().barcode();
+    $('hold_usr_textbox').select();
+    $('hold_usr_textbox').focus();
+    $('hold_usr_name').setAttribute(
+        'value',
+        patron.util.format_name(au_obj)
+    );
+    $('hold_usr_textbox').addEventListener(
+        'change',
+        function(ev) {
+            try {
+                oils_lock_page();
+                var au_obj = patron.util.retrieve_fleshed_au_via_barcode(
+                    ses(),
+                    ev.target.value
+                );
+                if (typeof au_obj.textcode == 'undefined') {
+                    hold_usr = au_obj.id();
+                    $('hold_usr_name').setAttribute(
+                        'value',
+                        patron.util.format_name(au_obj)
+                    );
+                    removeCSSClass($('hold_usr_name'),'failure_text');
+                } else {
+                    hold_usr = null;
+                    $('hold_usr_name').setAttribute(
+                        'value',
+                        $('patronStrings').getString('staff.item.batch.hold.user_not_found')
+                    );
+                    addCSSClass($('hold_usr_name'),'failure_text');
+                }
+            } catch(E) {
+                alert('Error in place_hold.js, hold_usr handler: ' + E);
+            }
+        },
+        false
+    );
+}
+
+function populate_pickup_lib_menu() {
+    try {
+        JSAN.use('util.widgets');
+        JSAN.use('util.functional');
+
+        util.widgets.remove_children('pickup_lib_menu_placeholder');
+
+        var list = util.functional.map_list(
+            data.list.aou,
+            function(o) {
+                var sname = o.shortname();
+                for (i = sname.length; i < 20; i++) sname += ' ';
+                return [
+                    o.name() ? sname + ' ' + o.name() : o.shortname(),
+                    o.id(),
+                    ( !isTrue(data.hash.aout[ o.ou_type() ].can_have_users()) ),
+                    ( data.hash.aout[ o.ou_type() ].depth() * 2),
+                ];
+            }
+        );
+        ml = util.widgets.make_menulist( list, data.list.au[0].ws_ou() );
+        ml.setAttribute('id','pickup_lib_menu');
+
+        $('pickup_lib_menu_placeholder').appendChild(ml);
+
+        ml.addEventListener(
+            'command',
+            function(ev) { oils_lock_page(); },
+            false
+        );
+
+    } catch(E) {
+        alert('Error in place_hold.js, populate_pickup_lib_menu(): ' + E);
+    } 
+}
+
+function ui_setup() {
+    netscape.security.PrivilegeManager.enablePrivilege(
+        "UniversalXPConnect");
+    if (typeof JSAN == 'undefined') {
+        throw( "The JSAN library object is missing.");
+    }
+    JSAN.errorLevel = "die"; // none, warn, or die
+    JSAN.addRepository('/xul/server/');
+    JSAN.use('util.error');
+    error = new util.error();
+
+    if (typeof xulG == 'object' && typeof xulG.set_tab_name == 'function') {
+        try {
+            xulG.set_tab_name(
+                $('patronStrings').getString('staff.item.batch.hold.tab_name')
+            );
+        } catch(E) {
+            alert(E);
+        }
+    }
+
+}
diff --git a/Open-ILS/xul/staff_client/server/patron/place_hold.xul b/Open-ILS/xul/staff_client/server/patron/place_hold.xul
new file mode 100644
index 0000000..afa0a55
--- /dev/null
+++ b/Open-ILS/xul/staff_client/server/patron/place_hold.xul
@@ -0,0 +1,105 @@
+<?xml version="1.0"?>
+<!-- Application: Evergreen Staff Client -->
+<!-- Screen: Item Hold/Recall Placement -->
+
+<!-- /////////////////////////////////////////////////////////////////////// -->
+<!-- STYLESHEETS -->
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="/xul/server/skin/global.css" type="text/css"?>
+
+<!-- /////////////////////////////////////////////////////////////////////// -->
+<!-- LOCALIZATION -->
+<!DOCTYPE window PUBLIC "" ""[
+    <!--#include virtual="/opac/locale/${locale}/lang.dtd"-->
+]>
+
+<!-- /////////////////////////////////////////////////////////////////////// -->
+<!-- OVERLAYS -->
+<?xul-overlay href="/xul/server/OpenILS/util_overlay.xul"?>
+
+<window id="place_hold_win" 
+    onload="try{my_init();font_helper();persist_helper();}catch(E){alert(E);}"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+    <!-- /////////////////////////////////////////////////////////////////// -->
+    <!-- BEHAVIOR -->
+    <script type="text/javascript">
+        var myPackageDir = 'open_ils_staff_client'; var IAMXUL = true;
+    </script>
+    <scripts id="openils_util_scripts"/>
+
+    <messagecatalog id="patronStrings"
+        src='/xul/server/locale/<!--#echo var="locale"-->/patron.properties'/>
+
+    <script type="text/javascript" src="/xul/server/main/JSAN.js"/>
+    <script type="text/javascript" src="place_hold.js"/>
+
+    <vbox flex="1">
+    <groupbox>
+        <caption label="&staff.item.batch.hold.groupbox_caption;"/>
+
+        <grid>
+            <columns>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <label control="hold_usr_textbox"
+                        value="&staff.item.batch.hold.hold_usr.label;"
+                        accesskey="&staff.item.batch.hold.hold_usr.accesskey;"/>
+                    <textbox id="hold_usr_textbox"/>
+                </row>
+                <row>
+                    <spacer/>
+                    <label id="hold_usr_name"/>
+                </row>
+                <row>
+                    <label control="hold_type_menu"
+                        value="&staff.item.batch.hold.hold_type_menu.label;"
+                        accesskey="&staff.item.batch.hold.hold_type_menu.accesskey;"/>
+                    <hbox>
+                        <menulist id="hold_type_menu" oils_persist="value">
+                            <menupopup>
+                                <menuitem value="C"
+                                    label="&staff.item.batch.hold.hold_type_menuentry.copy_hold;"/>
+                                <menuitem value="R"
+                                    label="&staff.item.batch.hold.hold_type_menuentry.recall_hold;"/>
+                                <menuitem value="F"
+                                    label="&staff.item.batch.hold.hold_type_menuentry.force_hold;"/>
+                            </menupopup>
+                        </menulist>
+                    </hbox>
+                </row>
+                <row>
+                    <label
+                        value="&staff.item.batch.hold.pick_up_lib_menu.label;"
+                        accesskey="&staff.item.batch.hold.pick_up_lib_menu.accesskey;"/>
+                    <hbox id="pickup_lib_menu_placeholder"/>
+                </row>
+                <row>
+                    <spacer/>
+                    <hbox>
+                        <button id="cancel_btn"
+                            label="&staff.item.batch.hold.cancel_btn.label;"
+                            accesskey="&staff.item.batch.hold.cancel_btn.accesskey;"/>
+                        <button id="request_btn"
+                            label="&staff.item.batch.hold.request_btn.label;"
+                            accesskey="&staff.item.batch.hold.request_btn.accesskey;"/>
+                        <progressmeter id="progress_meter"
+                            mode="undetermined"
+                            hidden="true" />
+                    </hbox>
+                </row>
+            </rows>
+        </grid>
+
+    </groupbox>
+    <description id="desc" hidden="true">
+        &staff.item.batch.hold.failures_and_settings;
+    </description>
+    <vbox id="msgs" flex="1" class="my_overflow"/>
+    </vbox>
+
+</window>
+

-----------------------------------------------------------------------

Summary of changes:
 .../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


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list