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

Evergreen Git git at git.evergreen-ils.org
Tue Jan 10 15:15:07 EST 2012


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  df57275f7715752aeb1c6877a55072710711bb1a (commit)
       via  0ba1080ee1277006e6c41ba299c542994e470358 (commit)
       via  39547dfaf09f713bce63a3b9c5060d5bae1a3538 (commit)
       via  3cc27e764c9697e878ac9e0bff0db898f54e15b6 (commit)
       via  287c24981f942e25dfb618b848e0a5f519c23e5c (commit)
       via  5d5a8ee133546163ad48e461c85f9008959eebbd (commit)
       via  a727a91b26716a0df36c93c7962240bec231c180 (commit)
      from  ab38f007589704ef5e63e69b7b2db02662b13ba5 (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 df57275f7715752aeb1c6877a55072710711bb1a
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Jan 10 15:14:59 2012 -0500

    Terminology adjustment to reduce conflicts with the term "recall"
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index d16b927..4865bdd 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -1452,7 +1452,7 @@ INSERT INTO permission.perm_list ( id, code, description ) VALUES
  ( 517, 'COPY_HOLDS_FORCE', oils_i18n_gettext( 517, 
     'Allow a user to place a force hold on a specific copy', 'ppl', 'description' )),
  ( 518, 'COPY_HOLDS_RECALL', oils_i18n_gettext( 518, 
-    'Allow a user to place a recall hold on a specific copy', 'ppl', 'description' ));
+    'Allow a user to place a cataloging recall on a specific copy', 'ppl', 'description' ));
 
 SELECT SETVAL('permission.perm_list_id_seq'::TEXT, 1000);
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql b/Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql
index 85cc020..565aa72 100644
--- a/Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql
@@ -13,7 +13,7 @@ INSERT INTO permission.perm_list ( id, code, description ) VALUES
  ( 517, 'COPY_HOLDS_FORCE', oils_i18n_gettext( 517, 
     'Allow a user to place a force hold on a specific copy', 'ppl', 'description' )),
  ( 518, 'COPY_HOLDS_RECALL', oils_i18n_gettext( 518, 
-    'Allow a user to place a recall hold on a specific copy', 'ppl', 'description' ));
+    'Allow a user to place a cataloging recall on a specific copy', 'ppl', 'description' ));
 
 
 COMMIT;

commit 0ba1080ee1277006e6c41ba299c542994e470358
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Jan 10 15:13:58 2012 -0500

    Stamping force and recall hold permission addition script
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index ad239dd..fbe6210 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -86,7 +86,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0668', :eg_version); -- tsbere/miker
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0669', :eg_version); -- tsbere/miker
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql b/Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql
new file mode 100644
index 0000000..85cc020
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql
@@ -0,0 +1,19 @@
+-- Evergreen DB patch 0669.data.recall_and_force_holds.sql
+--
+-- FIXME: insert description of change, if needed
+--
+BEGIN;
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0669', :eg_version);
+
+-- FIXME: add/check SQL statements to perform the upgrade
+INSERT INTO permission.perm_list ( id, code, description ) VALUES
+ ( 517, 'COPY_HOLDS_FORCE', oils_i18n_gettext( 517, 
+    'Allow a user to place a force hold on a specific copy', 'ppl', 'description' )),
+ ( 518, 'COPY_HOLDS_RECALL', oils_i18n_gettext( 518, 
+    'Allow a user to place a recall hold on a specific copy', 'ppl', 'description' ));
+
+
+COMMIT;
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.copy_holds.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.copy_holds.sql
deleted file mode 100644
index 3575dc3..0000000
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.copy_holds.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-INSERT INTO permission.perm_list ( id, code, description ) VALUES
- ( 517, 'COPY_HOLDS_FORCE', oils_i18n_gettext( 517, 
-    'Allow a user to place a force hold on a specific copy', 'ppl', 'description' )),
- ( 518, 'COPY_HOLDS_RECALL', oils_i18n_gettext( 518, 
-    'Allow a user to place a recall hold on a specific copy', 'ppl', 'description' ));

commit 39547dfaf09f713bce63a3b9c5060d5bae1a3538
Author: Thomas Berezansky <tsbere at mvlc.org>
Date:   Thu Oct 6 09:13:38 2011 -0400

    Completing Force/Recall Holds
    
    Add support for the Force and Recall hold types to be something other than
    just aliases of Copy holds.
    
    Both holds are made to cut in line over *all* other holds and both ignore
    all hold rules, including copy, location, and status holdable flags.
    
    Recall holds, when they reach their destination, will be flagged to be sent
    to cataloging.
    
    In addition, to place either kind of hold you need a new permission at the
    copy's circulation library:
    
    COPY_HOLD_FORCE for force holds
    COPY_HOLD_RECALL for recall holds
    
    Also, some re-ordering of logic should result in a fix for issues with
    capturing holds as transits and/or suppressing holds and the hold shelf
    logic.
    
    Signed-off-by: Thomas Berezansky <tsbere at mvlc.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
index 999ac68..e5d572c 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
@@ -2511,6 +2511,17 @@ sub do_checkin {
                 $self->fake_hold_dest(0);
                 return if $self->bail_out;
 
+            } elsif ($hold and $hold->hold_type eq 'R') {
+
+                $self->copy->status(OILS_COPY_STATUS_CATALOGING);
+                $self->notify_hold(0); # No need to notify
+                $self->fake_hold_dest(0);
+                $self->noop(1); # Don't try and capture for other holds/transits now
+                $self->update_copy();
+                $hold->fulfillment_time('now');
+                $self->bail_on_events($self->editor->event)
+                    unless $self->editor->update_action_hold_request($hold);
+
             } else {
 
                 # hold transited to correct location
@@ -2911,12 +2922,24 @@ sub attempt_checkin_hold_capture {
 
     $self->retarget($retarget);
 
+    my $suppress_transit = 0;
+    if( $hold->pickup_lib != $self->circ_lib and not $self->hold_as_transit ) {
+        my $suppress_transit_circ = $U->ou_ancestor_setting($self->circ_lib, 'circ.transit.suppress_hold');
+        if($suppress_transit_circ && $suppress_transit_circ->{value}) {
+            my $suppress_transit_pickup = $U->ou_ancestor_setting($hold->pickup_lib, 'circ.transit.suppress_hold');
+            if($suppress_transit_pickup && $suppress_transit_circ->{value} eq $suppress_transit_pickup->{value}) {
+                $suppress_transit = 1;
+                $self->hold->pickup_lib($self->circ_lib);
+            }
+        }
+    }
+
     $logger->info("circulator: found permitted hold ".$hold->id." for copy, capturing...");
 
     $hold->current_copy($copy->id);
     $hold->capture_time('now');
     $self->put_hold_on_shelf($hold) 
-        if $hold->pickup_lib == $self->circ_lib;
+        if ($suppress_transit || ($hold->pickup_lib == $self->circ_lib and not $self->hold_as_transit) );
 
     # prevent DB errors caused by fetching 
     # holds from storage, and updating through cstore
@@ -2934,26 +2957,22 @@ sub attempt_checkin_hold_capture {
 
     return 0 if $self->bail_out;
 
-    my $suppress_transit = 0;
-    if( $hold->pickup_lib != $self->circ_lib and not $self->hold_as_transit ) {
-        my $suppress_transit_circ = $U->ou_ancestor_setting($self->circ_lib, 'circ.transit.suppress_hold');
-        if($suppress_transit_circ && $suppress_transit_circ->{value}) {
-            my $suppress_transit_pickup = $U->ou_ancestor_setting($hold->pickup_lib, 'circ.transit.suppress_hold');
-            if($suppress_transit_pickup && $suppress_transit_circ->{value} eq $suppress_transit_pickup->{value}) {
-                $suppress_transit = 1;
-                $self->hold->pickup_lib($self->circ_lib);
-            }
-        }
-    }
-
     if( $suppress_transit or ( $hold->pickup_lib == $self->circ_lib && not $self->hold_as_transit ) ) {
 
-        # This hold was captured in the correct location
-        $copy->status(OILS_COPY_STATUS_ON_HOLDS_SHELF);
-        $self->push_events(OpenILS::Event->new('SUCCESS'));
+        if ($hold->hold_type eq 'R') {
+            $copy->status(OILS_COPY_STATUS_CATALOGING);
+            $hold->fulfillment_time('now');
+            $self->noop(1); # Block other transit/hold checks
+            $self->bail_on_events($self->editor->event)
+                unless $self->editor->update_action_hold_request($hold);
+        } else {
+            # This hold was captured in the correct location
+            $copy->status(OILS_COPY_STATUS_ON_HOLDS_SHELF);
+            $self->push_events(OpenILS::Event->new('SUCCESS'));
 
-        #$self->do_hold_notify($hold->id);
-        $self->notify_hold($hold->id);
+            #$self->do_hold_notify($hold->id);
+            $self->notify_hold($hold->id);
+        }
 
     } else {
     
@@ -2967,6 +2986,7 @@ sub attempt_checkin_hold_capture {
 
     # make sure we save the copy status
     $self->update_copy;
+    return 0 if $copy->status == OILS_COPY_STATUS_CATALOGING;
     return 1;
 }
 
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 49558b8..d083747 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
@@ -288,10 +288,14 @@ sub create_hold {
         return $e->die_event unless $e->allowed('ISSUANCE_HOLDS', $porg);
     } elsif ( $t eq OILS_HOLD_TYPE_COPY ) {
         return $e->die_event unless $e->allowed('COPY_HOLDS',   $porg);
-    } elsif ( $t eq OILS_HOLD_TYPE_FORCE ) {
-        return $e->die_event unless $e->allowed('COPY_HOLDS',   $porg);
-    } elsif ( $t eq OILS_HOLD_TYPE_RECALL ) {
-        return $e->die_event unless $e->allowed('COPY_HOLDS',   $porg);
+    } elsif ( $t eq OILS_HOLD_TYPE_FORCE || $t eq OILS_HOLD_TYPE_RECALL ) {
+		my $copy = $e->retrieve_asset_copy($hold->target)
+			or return $e->die_event;
+        if ( $t eq OILS_HOLD_TYPE_FORCE ) {
+            return $e->die_event unless $e->allowed('COPY_HOLDS_FORCE',   $copy->circ_lib);
+        } elsif ( $t eq OILS_HOLD_TYPE_RECALL ) {
+            return $e->die_event unless $e->allowed('COPY_HOLDS_RECALL',   $copy->circ_lib);
+        }
     }
 
     if( @events ) {
@@ -2285,6 +2289,7 @@ sub do_possibility_checks {
         return $e->event unless $volume = $e->retrieve_asset_call_number($copy->call_number);
         return $e->event unless $title  = $e->retrieve_biblio_record_entry($volume->record);
 
+        return (1, 1, []) if( $hold_type eq OILS_HOLD_TYPE_RECALL || $hold_type eq OILS_HOLD_TYPE_FORCE);
         return verify_copy_for_hold( 
             $patron, $e->requestor, $title, $copy, $pickup_lib, $request_lib
         );
@@ -2848,10 +2853,6 @@ sub find_nearest_permitted_hold {
 		} 
 	);
 
-	# hold->type "R" means we need this copy
-	for my $h (@$old_holds) { return ($h) if $h->hold_type eq 'R'; }
-
-
     my $hold_stall_interval = $U->ou_ancestor_setting_value($user->ws_ou, OILS_SETTING_HOLD_SOFT_STALL);
 
 	$logger->info("circulator: searching for best hold at org ".$user->ws_ou.
@@ -3519,7 +3520,7 @@ sub hold_has_copy_at {
         limit => 1
     };
 
-    if($hold_type eq 'C') {
+    if($hold_type eq 'C' or $hold_type eq 'F' or $hold_type eq 'R') {
 
         $query->{where}->{'+acp'}->{id} = $hold_target;
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
index d58e213..10f309f 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
@@ -307,7 +307,7 @@ sub nearest_hold {
 		  	AND h.cancel_time IS NULL
 		  	AND (h.expire_time IS NULL OR h.expire_time > NOW())
             AND h.frozen IS FALSE
-		ORDER BY $holdsort
+		ORDER BY CASE WHEN h.hold_type IN ('R','F') THEN 0 ELSE 1 END, $holdsort
 		LIMIT $limit
 	SQL
 	
@@ -1039,7 +1039,7 @@ sub new_hold_copy_targeter {
 							  frozen => 'f',
 							  prev_check_time => { '<=' => $expire_threshold },
 							},
-							{ order_by => 'CASE WHEN hold_type = \'F\' THEN 0 ELSE 1 END, selection_depth DESC, request_time,prev_check_time' } ) ];
+							{ order_by => 'selection_depth DESC, request_time,prev_check_time' } ) ];
 
 			# find all the holds holds needing first time targeting
 			push @$holds, action::hold_request->search(
@@ -1048,7 +1048,7 @@ sub new_hold_copy_targeter {
 				  			prev_check_time => undef,
 							frozen => 'f',
 							cancel_time => undef,
-							{ order_by => 'CASE WHEN hold_type = \'F\' THEN 0 ELSE 1 END, selection_depth DESC, request_time' } );
+							{ order_by => 'selection_depth DESC, request_time' } );
 		} else {
 
 			# find all the holds holds needing first time targeting ONLY
@@ -1058,7 +1058,7 @@ sub new_hold_copy_targeter {
 				  			prev_check_time => undef,
 							cancel_time => undef,
 							frozen => 'f',
-							{ order_by => 'CASE WHEN hold_type = \'F\' THEN 0 ELSE 1 END, selection_depth DESC, request_time' } ) ];
+							{ order_by => 'selection_depth DESC, request_time' } ) ];
 		}
 	} catch Error with {
 		my $e = shift;
@@ -1230,14 +1230,17 @@ sub new_hold_copy_targeter {
 				push @$all_copies, $_cp if $_cp;
 			}
 
-			# trim unholdables
-			@$all_copies = grep {	isTrue($_->status->holdable) && 
-						isTrue($_->location->holdable) && 
-						isTrue($_->holdable) &&
-						!isTrue($_->deleted) &&
-						(isTrue($hold->mint_condition) ? isTrue($_->mint_condition) : 1) &&
-						($hold->hold_type ne 'P' ? $_->part_maps->count == 0 : 1)
-					} @$all_copies;
+            # Force and recall holds bypass pretty much everything
+            if ($hold->hold_type ne 'R' && $hold->hold_type ne 'F') {
+    			# trim unholdables
+	    		@$all_copies = grep {	isTrue($_->status->holdable) && 
+		    				isTrue($_->location->holdable) && 
+			    			isTrue($_->holdable) &&
+				    		!isTrue($_->deleted) &&
+					    	(isTrue($hold->mint_condition) ? isTrue($_->mint_condition) : 1) &&
+						    ($hold->hold_type ne 'P' ? $_->part_maps->count == 0 : 1)
+    					} @$all_copies;
+            }
 
 			# let 'em know we're still working
 			$client->status( new OpenSRF::DomainObject::oilsContinueStatus );
@@ -1351,8 +1354,13 @@ sub new_hold_copy_targeter {
 
 			$all_copies = [grep { $_->status == 0 || $_->status == 7 } grep {''.$_->circ_lib ne $pu_lib } @good_copies];
 			# $all_copies is now a list of copies not at the pickup library
-
-			my $best = choose_nearest_copy($hold, $prox_list);
+			
+            my $best;
+            if  ($hold->hold_type eq 'R' || $hold->hold_type eq 'F') { # Recall/Force holds bypass hold rules.
+                $best = $good_copies[0] if(scalar @good_copies);
+            } else {
+                $best = choose_nearest_copy($hold, $prox_list);
+            }
 			$client->status( new OpenSRF::DomainObject::oilsContinueStatus );
 
 			if (!$best) {
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm
index 68d8c13..519382f 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm
@@ -461,7 +461,7 @@ sub __hold_to_title {
 
 	return __copy_to_title($e, 
 		$e->retrieve_asset_copy($hold->target)) 
-		if $hold->hold_type eq 'C';
+		if $hold->hold_type eq 'C' or $hold->hold_type eq 'F' or $hold->hold_type eq 'R';
 
 	return __volume_to_title($e, 
 		$e->retrieve_asset_call_number($hold->target))
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 3d725ff..d16b927 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -1448,7 +1448,11 @@ INSERT INTO permission.perm_list ( id, code, description ) VALUES
  ( 515, 'UPDATE_PATRON_PRIMARY_CARD', oils_i18n_gettext( 515,
     'Allows a user to manually adjust a patron''s primary card', 'ppl', 'description')),
  ( 516, 'CREATE_REPORT_TEMPLATE', oils_i18n_gettext( 516,
-    'Allows a user to create report templates', 'ppl', 'description' ));
+    'Allows a user to create report templates', 'ppl', 'description' )),
+ ( 517, 'COPY_HOLDS_FORCE', oils_i18n_gettext( 517, 
+    'Allow a user to place a force hold on a specific copy', 'ppl', 'description' )),
+ ( 518, 'COPY_HOLDS_RECALL', oils_i18n_gettext( 518, 
+    'Allow a user to place a recall hold on a specific copy', 'ppl', 'description' ));
 
 SELECT SETVAL('permission.perm_list_id_seq'::TEXT, 1000);
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.copy_holds.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.copy_holds.sql
new file mode 100644
index 0000000..3575dc3
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.copy_holds.sql
@@ -0,0 +1,5 @@
+INSERT INTO permission.perm_list ( id, code, description ) VALUES
+ ( 517, 'COPY_HOLDS_FORCE', oils_i18n_gettext( 517, 
+    'Allow a user to place a force hold on a specific copy', 'ppl', 'description' )),
+ ( 518, 'COPY_HOLDS_RECALL', oils_i18n_gettext( 518, 
+    'Allow a user to place a recall hold on a specific copy', 'ppl', 'description' ));

commit 3cc27e764c9697e878ac9e0bff0db898f54e15b6
Merge: 287c249 ab38f00
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Jan 10 15:11:07 2012 -0500

    Merge branch 'master' of git.evergreen-ils.org:Evergreen


commit 287c24981f942e25dfb618b848e0a5f519c23e5c
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Jan 10 15:03:57 2012 -0500

    Stamping upgrade script for in-db hold permit fixups
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index eaf5c15..ad239dd 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -86,7 +86,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0667', :eg_version); -- senator/berick
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0668', :eg_version); -- tsbere/miker
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.fix_indb_hold_permit.sql b/Open-ILS/src/sql/Pg/upgrade/0668.schema.fix_indb_hold_permit.sql
similarity index 96%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.fix_indb_hold_permit.sql
rename to Open-ILS/src/sql/Pg/upgrade/0668.schema.fix_indb_hold_permit.sql
index 35d2ba4..c26b336 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.fix_indb_hold_permit.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0668.schema.fix_indb_hold_permit.sql
@@ -1,3 +1,14 @@
+-- Evergreen DB patch 0668.schema.fix_indb_hold_permit.sql
+--
+-- FIXME: insert description of change, if needed
+--
+BEGIN;
+
+
+-- check whether patch can be applied
+SELECT evergreen.upgrade_deps_block_check('0668', :eg_version);
+
+-- FIXME: add/check SQL statements to perform the upgrade
 CREATE OR REPLACE FUNCTION action.hold_request_permit_test( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT, retargetting BOOL ) RETURNS SETOF action.matrix_test_result AS $func$
 DECLARE
     matchpoint_id        INT;
@@ -214,3 +225,6 @@ BEGIN
     RETURN;
 END;
 $func$ LANGUAGE plpgsql;
+
+
+COMMIT;

commit 5d5a8ee133546163ad48e461c85f9008959eebbd
Author: Thomas Berezansky <tsbere at mvlc.org>
Date:   Thu Oct 6 14:23:26 2011 -0400

    TPac messages for item/location/status not holdable
    
    Signed-off-by: Thomas Berezansky <tsbere at mvlc.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2 b/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2
index e79e81d..50a0ebf 100644
--- a/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2
+++ b/Open-ILS/src/templates/opac/parts/hold_error_messages.tt2
@@ -20,6 +20,9 @@
         "config.hold_matrix_test.holdable" => l("Hold rules reject this item as unholdable"),
         "config.hold_matrix_test.max_holds" => l("The patron has reached the maximum number of holds"),
         "config.rule_age_hold_protect.prox" => l("The item is too new to transit this far"),
+        "item.holdable" => l("The item is not holdable"),
+        "location.holdable" => l("The item's location is not holdable"),
+        "status.holdable" => l("The item is not in a holdable status"),
         "no_item" => l("The system could not find this item"),
         "no_ultimate_items" => l("The system could not find any items to match this hold request"),
         "no_matchpoint" => l("System rules do not define how to handle this item"),

commit a727a91b26716a0df36c93c7962240bec231c180
Author: Thomas Berezansky <tsbere at mvlc.org>
Date:   Thu Oct 6 11:48:21 2011 -0400

    Fix INDB hold permit holdable checking
    
    Check Item/Status/Location holdable flags
    
    Signed-off-by: Thomas Berezansky <tsbere at mvlc.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Utils/PermitHold.pm b/Open-ILS/src/perlmods/lib/OpenILS/Utils/PermitHold.pm
index 39bfaeb..c80a5d5 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Utils/PermitHold.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Utils/PermitHold.pm
@@ -201,6 +201,9 @@ sub check_age_protect {
 
 my $LEGACY_HOLD_EVENT_MAP = {
     'config.hold_matrix_test.holdable' => 'ITEM_NOT_HOLDABLE',
+    'item.holdable' => 'ITEM_NOT_HOLDABLE',
+    'location.holdable' => 'ITEM_NOT_HOLDABLE',
+    'status.holdable' => 'ITEM_NOT_HOLDABLE',
     'transit_range' => 'ITEM_NOT_HOLDABLE',
     'no_matchpoint' => 'NO_POLICY_MATCHPOINT',
     'config.hold_matrix_test.max_holds' => 'MAX_HOLDS',
diff --git a/Open-ILS/src/sql/Pg/110.hold_matrix.sql b/Open-ILS/src/sql/Pg/110.hold_matrix.sql
index 0bb95de..5131afb 100644
--- a/Open-ILS/src/sql/Pg/110.hold_matrix.sql
+++ b/Open-ILS/src/sql/Pg/110.hold_matrix.sql
@@ -224,6 +224,8 @@ DECLARE
     transit_source        actor.org_unit%ROWTYPE;
     item_object        asset.copy%ROWTYPE;
     item_cn_object     asset.call_number%ROWTYPE;
+    item_status_object  config.copy_status%ROWTYPE;
+    item_location_object    asset.copy_location%ROWTYPE;
     ou_skip              actor.org_unit_setting%ROWTYPE;
     result            action.matrix_test_result;
     hold_test        config.hold_matrix_matchpoint%ROWTYPE;
@@ -283,6 +285,10 @@ BEGIN
         RETURN;
     END IF;
 
+    SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+    SELECT INTO item_status_object * FROM config.copy_status WHERE id = item_object.status;
+    SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
+
     -- Fail if we couldn't find any matchpoint (requires a default)
     IF matchpoint_id IS NULL THEN
         result.fail_part := 'no_matchpoint';
@@ -301,6 +307,27 @@ BEGIN
         RETURN NEXT result;
     END IF;
 
+    IF item_object.holdable IS FALSE THEN
+        result.fail_part := 'item.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_status_object.holdable IS FALSE THEN
+        result.fail_part := 'status.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_location_object.holdable IS FALSE THEN
+        result.fail_part := 'location.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
     IF hold_test.transit_range IS NOT NULL THEN
         SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range;
         IF hold_test.distance_is_from_owner THEN
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.fix_indb_hold_permit.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.fix_indb_hold_permit.sql
new file mode 100644
index 0000000..35d2ba4
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.fix_indb_hold_permit.sql
@@ -0,0 +1,216 @@
+CREATE OR REPLACE FUNCTION action.hold_request_permit_test( pickup_ou INT, request_ou INT, match_item BIGINT, match_user INT, match_requestor INT, retargetting BOOL ) RETURNS SETOF action.matrix_test_result AS $func$
+DECLARE
+    matchpoint_id        INT;
+    user_object        actor.usr%ROWTYPE;
+    age_protect_object    config.rule_age_hold_protect%ROWTYPE;
+    standing_penalty    config.standing_penalty%ROWTYPE;
+    transit_range_ou_type    actor.org_unit_type%ROWTYPE;
+    transit_source        actor.org_unit%ROWTYPE;
+    item_object        asset.copy%ROWTYPE;
+    item_cn_object     asset.call_number%ROWTYPE;
+    item_status_object  config.copy_status%ROWTYPE;
+    item_location_object    asset.copy_location%ROWTYPE;
+    ou_skip              actor.org_unit_setting%ROWTYPE;
+    result            action.matrix_test_result;
+    hold_test        config.hold_matrix_matchpoint%ROWTYPE;
+    use_active_date   TEXT;
+    age_protect_date  TIMESTAMP WITH TIME ZONE;
+    hold_count        INT;
+    hold_transit_prox    INT;
+    frozen_hold_count    INT;
+    context_org_list    INT[];
+    done            BOOL := FALSE;
+BEGIN
+    SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+    SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( pickup_ou );
+
+    result.success := TRUE;
+
+    -- Fail if we couldn't find a user
+    IF user_object.id IS NULL THEN
+        result.fail_part := 'no_user';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
+
+    -- Fail if we couldn't find a copy
+    IF item_object.id IS NULL THEN
+        result.fail_part := 'no_item';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO matchpoint_id action.find_hold_matrix_matchpoint(pickup_ou, request_ou, match_item, match_user, match_requestor);
+    result.matchpoint := matchpoint_id;
+
+    SELECT INTO ou_skip * FROM actor.org_unit_setting WHERE name = 'circ.holds.target_skip_me' AND org_unit = item_object.circ_lib;
+
+    -- Fail if the circ_lib for the item has circ.holds.target_skip_me set to true
+    IF ou_skip.id IS NOT NULL AND ou_skip.value = 'true' THEN
+        result.fail_part := 'circ.holds.target_skip_me';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    -- Fail if user is barred
+    IF user_object.barred IS TRUE THEN
+        result.fail_part := 'actor.usr.barred';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+    SELECT INTO item_status_object * FROM config.copy_status WHERE id = item_object.status;
+    SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
+
+    -- Fail if we couldn't find any matchpoint (requires a default)
+    IF matchpoint_id IS NULL THEN
+        result.fail_part := 'no_matchpoint';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+        RETURN;
+    END IF;
+
+    SELECT INTO hold_test * FROM config.hold_matrix_matchpoint WHERE id = matchpoint_id;
+
+    IF hold_test.holdable IS FALSE THEN
+        result.fail_part := 'config.hold_matrix_test.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_object.holdable IS FALSE THEN
+        result.fail_part := 'item.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_status_object.holdable IS FALSE THEN
+        result.fail_part := 'status.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF item_location_object.holdable IS FALSE THEN
+        result.fail_part := 'location.holdable';
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END IF;
+
+    IF hold_test.transit_range IS NOT NULL THEN
+        SELECT INTO transit_range_ou_type * FROM actor.org_unit_type WHERE id = hold_test.transit_range;
+        IF hold_test.distance_is_from_owner THEN
+            SELECT INTO transit_source ou.* FROM actor.org_unit ou JOIN asset.call_number cn ON (cn.owning_lib = ou.id) WHERE cn.id = item_object.call_number;
+        ELSE
+            SELECT INTO transit_source * FROM actor.org_unit WHERE id = item_object.circ_lib;
+        END IF;
+
+        PERFORM * FROM actor.org_unit_descendants( transit_source.id, transit_range_ou_type.depth ) WHERE id = pickup_ou;
+
+        IF NOT FOUND THEN
+            result.fail_part := 'transit_range';
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END IF;
+    END IF;
+ 
+    FOR standing_penalty IN
+        SELECT  DISTINCT csp.*
+          FROM  actor.usr_standing_penalty usp
+                JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
+          WHERE usr = match_user
+                AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
+                AND (usp.stop_date IS NULL or usp.stop_date > NOW())
+                AND csp.block_list LIKE '%HOLD%' LOOP
+
+        result.fail_part := standing_penalty.name;
+        result.success := FALSE;
+        done := TRUE;
+        RETURN NEXT result;
+    END LOOP;
+
+    IF hold_test.stop_blocked_user IS TRUE THEN
+        FOR standing_penalty IN
+            SELECT  DISTINCT csp.*
+              FROM  actor.usr_standing_penalty usp
+                    JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
+              WHERE usr = match_user
+                    AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
+                    AND (usp.stop_date IS NULL or usp.stop_date > NOW())
+                    AND csp.block_list LIKE '%CIRC%' LOOP
+    
+            result.fail_part := standing_penalty.name;
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END LOOP;
+    END IF;
+
+    IF hold_test.max_holds IS NOT NULL AND NOT retargetting THEN
+        SELECT    INTO hold_count COUNT(*)
+          FROM    action.hold_request
+          WHERE    usr = match_user
+            AND fulfillment_time IS NULL
+            AND cancel_time IS NULL
+            AND CASE WHEN hold_test.include_frozen_holds THEN TRUE ELSE frozen IS FALSE END;
+
+        IF hold_count >= hold_test.max_holds THEN
+            result.fail_part := 'config.hold_matrix_test.max_holds';
+            result.success := FALSE;
+            done := TRUE;
+            RETURN NEXT result;
+        END IF;
+    END IF;
+
+    IF item_object.age_protect IS NOT NULL THEN
+        SELECT INTO age_protect_object * FROM config.rule_age_hold_protect WHERE id = item_object.age_protect;
+        IF hold_test.distance_is_from_owner THEN
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_cn_object.owning_lib);
+        ELSE
+            SELECT INTO use_active_date value FROM actor.org_unit_ancestor_setting('circ.holds.age_protect.active_date', item_object.circ_lib);
+        END IF;
+        IF use_active_date = 'true' THEN
+            age_protect_date := COALESCE(item_object.active_date, NOW());
+        ELSE
+            age_protect_date := item_object.create_date;
+        END IF;
+        IF age_protect_date + age_protect_object.age > NOW() THEN
+            IF hold_test.distance_is_from_owner THEN
+                SELECT INTO item_cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+                SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_cn_object.owning_lib AND to_org = pickup_ou;
+            ELSE
+                SELECT INTO hold_transit_prox prox FROM actor.org_unit_proximity WHERE from_org = item_object.circ_lib AND to_org = pickup_ou;
+            END IF;
+
+            IF hold_transit_prox > age_protect_object.prox THEN
+                result.fail_part := 'config.rule_age_hold_protect.prox';
+                result.success := FALSE;
+                done := TRUE;
+                RETURN NEXT result;
+            END IF;
+        END IF;
+    END IF;
+
+    IF NOT done THEN
+        RETURN NEXT result;
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE plpgsql;
diff --git a/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js b/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js
index b8e4225..30fb039 100644
--- a/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js
+++ b/Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js
@@ -31,6 +31,9 @@
     "FAIL_PART_config_circ_matrix_test_total_copy_hold_ratio": "The total item-to-hold ratio is too low",
     "FAIL_PART_config_hold_matrix_test_holdable": "Hold rules reject this item as unholdable",
     "FAIL_PART_config_hold_matrix_test_max_holds": "The patron has reached the maximum number of holds",
+    "FAIL_PART_item.holdable" => "The item is not holdable",
+    "FAIL_PART_location.holdable" => "The item's location is not holdable",
+    "FAIL_PART_status.holdable" => "The item is not in a holdable status",
     "FAIL_PART_config_rule_age_hold_protect_prox": "The item is too new to transit this far",
     "FAIL_PART_no_item": "The system could not find this item",
     "FAIL_PART_no_ultimate_items": "The system could not find any items to match this hold request",

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

Summary of changes:
 .../lib/OpenILS/Application/Circ/Circulate.pm      |   56 +++++++++++++------
 .../perlmods/lib/OpenILS/Application/Circ/Holds.pm |   19 ++++---
 .../Application/Storage/Publisher/action.pm        |   36 ++++++++-----
 Open-ILS/src/perlmods/lib/OpenILS/SIP/Patron.pm    |    2 +-
 .../src/perlmods/lib/OpenILS/Utils/PermitHold.pm   |    3 +
 Open-ILS/src/sql/Pg/002.schema.config.sql          |    2 +-
 Open-ILS/src/sql/Pg/110.hold_matrix.sql            |   27 +++++++++
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |    6 ++-
 ...ir.sql => 0668.schema.fix_indb_hold_permit.sql} |   37 ++++++++++++--
 .../upgrade/0669.data.recall_and_force_holds.sql   |   19 +++++++
 .../templates/opac/parts/hold_error_messages.tt2   |    3 +
 Open-ILS/web/js/dojo/openils/circ/nls/selfcheck.js |    3 +
 12 files changed, 165 insertions(+), 48 deletions(-)
 copy Open-ILS/src/sql/Pg/upgrade/{0651.schema.unnest-hold-permit-upgrade-script-repair.sql => 0668.schema.fix_indb_hold_permit.sql} (86%)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/0669.data.recall_and_force_holds.sql


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list