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

Evergreen Git git at git.evergreen-ils.org
Tue Jul 24 11:51:36 EDT 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  967a96332af446b7224e4c236b6a3a87f601b2a1 (commit)
       via  ef0842aba78178d9df85c1edbfb295c54109630a (commit)
       via  bd98f2adea3937bd848cf0386e8220095e3d8118 (commit)
       via  fecdfe5dcb1a87cd2b12733b4b06c56e5c5ab4b5 (commit)
       via  08075458b3fad3d9112d8dc2f2f6655056f8513d (commit)
       via  169731b8569a378bae748c98514e42bd89954d17 (commit)
       via  1b36e7a6af73c06417a4cbf19bf0585125b32a36 (commit)
       via  266fc54ebaab9806af3ee86ba39b778bc192ebf8 (commit)
       via  a8155fc4c4728adbfd3e734a9ede7eca1f067c78 (commit)
       via  ae0e26ed0862b3694415806ce2dc05e128868c24 (commit)
      from  ea3a318233a63168882f93945add1cdd8a18ff61 (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 967a96332af446b7224e4c236b6a3a87f601b2a1
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Jul 24 11:51:29 2012 -0400

    Stamping upgrade script for Capture/Fulfill penalty blocks
    
    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 a527fd3..bfcc219 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -87,7 +87,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 ('0720', :eg_version); -- berick/miker
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0721', :eg_version); -- berick/miker
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql b/Open-ILS/src/sql/Pg/upgrade/0721.data.hold_cap_fill_penalty_blocks.sql
similarity index 99%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
rename to Open-ILS/src/sql/Pg/upgrade/0721.data.hold_cap_fill_penalty_blocks.sql
index 2b991a9..9046c47 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0721.data.hold_cap_fill_penalty_blocks.sql
@@ -1,6 +1,8 @@
 
 BEGIN;
 
+SELECT evergreen.upgrade_deps_block_check('0721', :eg_version);
+
 UPDATE config.standing_penalty 
     SET block_list = REPLACE(block_list, 'HOLD', 'HOLD|CAPTURE') 
     WHERE   

commit ef0842aba78178d9df85c1edbfb295c54109630a
Author: Bill Erickson <berick at esilibrary.com>
Date:   Tue Jul 17 09:19:46 2012 -0400

    Apply HOLD block on new holds, CAPTURE block on existing
    
    With the addition of the CAPTURE block, the HOLD block should only apply
    for newly placed holds in the hold permit test
    (action.hold_request_permit_test).
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/110.hold_matrix.sql b/Open-ILS/src/sql/Pg/110.hold_matrix.sql
index 5131afb..be2ff65 100644
--- a/Open-ILS/src/sql/Pg/110.hold_matrix.sql
+++ b/Open-ILS/src/sql/Pg/110.hold_matrix.sql
@@ -236,12 +236,20 @@ DECLARE
     frozen_hold_count    INT;
     context_org_list    INT[];
     done            BOOL := FALSE;
+    hold_penalty TEXT;
 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;
 
+    -- The HOLD penalty block only applies to new holds.
+    -- The CAPTURE penalty block applies to existing holds.
+    hold_penalty := 'HOLD';
+    IF retargetting THEN
+        hold_penalty := 'CAPTURE';
+    END IF;
+
     -- Fail if we couldn't find a user
     IF user_object.id IS NULL THEN
         result.fail_part := 'no_user';
@@ -353,7 +361,7 @@ BEGIN
           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
+                AND csp.block_list LIKE '%' || hold_penalty || '%' LOOP
 
         result.fail_part := standing_penalty.name;
         result.success := FALSE;
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
index 560cf29..2b991a9 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
@@ -1,4 +1,5 @@
 
+BEGIN;
 
 UPDATE config.standing_penalty 
     SET block_list = REPLACE(block_list, 'HOLD', 'HOLD|CAPTURE') 
@@ -18,3 +19,231 @@ UPDATE config.standing_penalty
         AND block_list NOT LIKE '%FULFILL%'; 
 
 
+-- apply the HOLD vs CAPTURE block logic
+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;
+    hold_penalty TEXT;
+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;
+
+    -- The HOLD penalty block only applies to new holds.
+    -- The CAPTURE penalty block applies to existing holds.
+    hold_penalty := 'HOLD';
+    IF retargetting THEN
+        hold_penalty := 'CAPTURE';
+    END IF;
+
+    -- 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_penalty || '%' 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;
+
+
+COMMIT;

commit bd98f2adea3937bd848cf0386e8220095e3d8118
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Jun 21 14:37:11 2012 -0400

    Avoid CAPTURE-blocked holds in pull list (IDL view)
    
    Update the new IDL holds pull list view to avoid returning holds for
    users that have CAPTURE penalties.
    
    Note that items are blocked from the pull list only if the hold pickup
    lib is within the CAPTURE penalty org unit range.  This means that users
    could be blocked at one branch, but use a pickup lib at another to avoid
    the block.  To prevent this type of abuse, set the org_depth to 0 on any
    penalties that apply the CAPTURE block.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index a3cda7c..dba33cf 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -5048,6 +5048,18 @@ SELECT  usr,
 		JOIN asset.call_number_prefix acnp ON (acn.prefix = acnp.id)
 		JOIN asset.call_number_suffix acns ON (acn.suffix = acns.id)
 		JOIN actor.usr au ON (au.id = ahr.usr)
+		LEFT JOIN actor.usr_standing_penalty ausp 
+			ON (ahr.usr = ausp.usr AND (ausp.stop_date IS NULL OR ausp.stop_date > NOW()))
+		LEFT JOIN config.standing_penalty csp
+			ON (
+				csp.id = ausp.standing_penalty AND 
+				csp.block_list LIKE '%CAPTURE%' AND (
+					(csp.org_depth IS NULL AND ahr.pickup_lib = ausp.org_unit) OR
+					(csp.org_depth IS NOT NULL AND ahr.pickup_lib IN (
+						SELECT id FROM actor.org_unit_descendants(ausp.org_unit, csp.org_depth))
+					)
+				)
+			)
 		LEFT JOIN serial.issuance siss
 			ON (ahr.hold_type = 'I' AND siss.id = ahr.target)
 		LEFT JOIN asset.copy_location_order acplo
@@ -5056,6 +5068,7 @@ SELECT  usr,
 		WHERE
 			ahr.capture_time IS NULL AND
 			ahr.cancel_time IS NULL AND
+			csp.id IS NULL AND
 			(ahr.expire_time is NULL OR ahr.expire_time > NOW())
 		]]></oils_persist:source_definition>
 		<fields oils_persist:primary="id">

commit fecdfe5dcb1a87cd2b12733b4b06c56e5c5ab4b5
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Jun 21 14:26:25 2012 -0400

    hold CAP/FILL blocks : pair FULFILL with CIRC in stock penalties
    
    FULFILL is really a block on circulation, not holds, so pair the FULFILL
    block with CIRC blocks for the stock data.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    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 0c0744c..f76ae20 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -20,13 +20,13 @@ INSERT INTO config.standing (id, value) VALUES (2, oils_i18n_gettext(2, 'Barred'
 SELECT SETVAL('config.standing_id_seq'::TEXT, 100);
 
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
-	VALUES (1,'PATRON_EXCEEDS_FINES',oils_i18n_gettext(1, 'Patron exceeds fine threshold', 'csp', 'label'),'CIRC|HOLD|CAPTURE|FULFILL|RENEW', TRUE);
+	VALUES (1,'PATRON_EXCEEDS_FINES',oils_i18n_gettext(1, 'Patron exceeds fine threshold', 'csp', 'label'),'CIRC|FULFILL|HOLD|CAPTURE|RENEW', TRUE);
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
-	VALUES (2,'PATRON_EXCEEDS_OVERDUE_COUNT',oils_i18n_gettext(2, 'Patron exceeds max overdue item threshold', 'csp', 'label'),'CIRC|HOLD|CAPTURE|FULFILL|RENEW', TRUE);
+	VALUES (2,'PATRON_EXCEEDS_OVERDUE_COUNT',oils_i18n_gettext(2, 'Patron exceeds max overdue item threshold', 'csp', 'label'),'CIRC|FULFILL|HOLD|CAPTURE|RENEW', TRUE);
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
-	VALUES (3,'PATRON_EXCEEDS_CHECKOUT_COUNT',oils_i18n_gettext(3, 'Patron exceeds max checked out item threshold', 'csp', 'label'),'CIRC', TRUE);
+	VALUES (3,'PATRON_EXCEEDS_CHECKOUT_COUNT',oils_i18n_gettext(3, 'Patron exceeds max checked out item threshold', 'csp', 'label'),'CIRC|FULFILL', TRUE);
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
-	VALUES (4,'PATRON_EXCEEDS_COLLECTIONS_WARNING',oils_i18n_gettext(4, 'Patron exceeds pre-collections warning fine threshold', 'csp', 'label'),'CIRC|HOLD|CAPTURE|FULFILL|RENEW', TRUE);
+	VALUES (4,'PATRON_EXCEEDS_COLLECTIONS_WARNING',oils_i18n_gettext(4, 'Patron exceeds pre-collections warning fine threshold', 'csp', 'label'),'CIRC|FULFILL|HOLD|CAPTURE|RENEW', TRUE);
 
 INSERT INTO config.standing_penalty (id,name,label,staff_alert) VALUES (20,'ALERT_NOTE',oils_i18n_gettext(20, 'Alerting Note, no blocks', 'csp', 'label'),TRUE);
 INSERT INTO config.standing_penalty (id,name,label) VALUES (21,'SILENT_NOTE',oils_i18n_gettext(21, 'Note, no blocks', 'csp', 'label'));
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
index b2c25c3..560cf29 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
@@ -1,11 +1,20 @@
 
 
 UPDATE config.standing_penalty 
-    SET block_list = REPLACE(block_list, 'HOLD', 'HOLD|CAPTURE|FULFILL') 
+    SET block_list = REPLACE(block_list, 'HOLD', 'HOLD|CAPTURE') 
+    WHERE   
+        -- STAFF_ penalties have names that match their block list
+        name NOT LIKE 'STAFF_%' 
+        -- belt & suspenders, also good for testing
+        AND block_list NOT LIKE '%CAPTURE%'; 
+
+ -- CIRC|FULFILL is now the same as CIRC previously was by itself
+UPDATE config.standing_penalty 
+    SET block_list = REPLACE(block_list, 'CIRC', 'CIRC|FULFILL') 
     WHERE   
         -- STAFF_ penalties have names that match their block list
         name NOT LIKE 'STAFF_%' 
         -- belt & suspenders, also good for testing
-        AND block_list NOT LIKE '%CAPTURE%' 
         AND block_list NOT LIKE '%FULFILL%'; 
 
+

commit 08075458b3fad3d9112d8dc2f2f6655056f8513d
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Jun 21 14:11:47 2012 -0400

    hold CAP/FILL blocks : more event test collection repairs
    
    Further improving the logic which decides which patron permit events are
    valid for a given set of circumstances.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson 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 8139155..262e0ba 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
@@ -1104,23 +1104,26 @@ sub run_patron_permit_scripts {
             if ($self->is_noncat) {
                 # no_item result is OK during noncat checkout
                 @trimmed_results = grep { ($_->{fail_part} || '') ne 'no_item' } @$results;
+
             } else {
-                @trimmed_results = @$results;
-            }
 
-            if ($self->checkout_is_for_hold) {
-                # if this checkout will fulfill a hold, ignore CIRC blocks
-                # and rely instead on the (later-checked) FULFILL block
+                if ($self->checkout_is_for_hold) {
+                    # if this checkout will fulfill a hold, ignore CIRC blocks
+                    # and rely instead on the (later-checked) FULFILL block
 
-                my @pen_names = grep {$_} map {$_->{fail_part}} @$results;
-                my $fblock_pens = $self->editor->search_config_standing_penalty(
-                    {name => [@pen_names], block_list => {like => '%CIRC%'}});
+                    my @pen_names = grep {$_} map {$_->{fail_part}} @$results;
+                    my $fblock_pens = $self->editor->search_config_standing_penalty(
+                        {name => [@pen_names], block_list => {like => '%CIRC%'}});
+
+                    for my $res (@$results) {
+                        my $name = $res->{fail_part} || '';
+                        next if grep {$_->name eq $name} @$fblock_pens;
+                        push(@trimmed_results, $res);
+                    }
 
-                for my $res (@$results) {
-                    my $name = $res->{fail_part} || '';
-                    next if grep {$_->name eq $name} @$fblock_pens or 
-                        ($self->is_noncat and $name eq 'no_item');
-                    push(@trimmed_results, $res);
+                } else { 
+                    # not for hold or noncat
+                    @trimmed_results = @$results;
                 }
             }
 

commit 169731b8569a378bae748c98514e42bd89954d17
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Jun 21 14:00:51 2012 -0400

    hold CAP/FILL blocks : repair event test in patron permit
    
    Repairs in oversight in the patron permit event testing code that caused
    the test to miss events when the checkout was not there to fulfill a
    hold.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson 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 7a30879..8139155 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
@@ -1104,6 +1104,8 @@ sub run_patron_permit_scripts {
             if ($self->is_noncat) {
                 # no_item result is OK during noncat checkout
                 @trimmed_results = grep { ($_->{fail_part} || '') ne 'no_item' } @$results;
+            } else {
+                @trimmed_results = @$results;
             }
 
             if ($self->checkout_is_for_hold) {

commit 1b36e7a6af73c06417a4cbf19bf0585125b32a36
Author: Bill Erickson <berick at esilibrary.com>
Date:   Tue Apr 10 16:24:59 2012 -0400

    Avoid CAPTURE-blocked holds in pull list
    
    Otherwise, staff will be pulling items for holds that cannot be
    captured.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

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 78b0596..d80fbaf 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
@@ -505,10 +505,15 @@ sub hold_pull_list {
 		  FROM	$h_table h
 		  	JOIN $a_table a ON (h.current_copy = a.id)
 		  	LEFT JOIN $ord_table ord ON (a.location = ord.location AND a.circ_lib = ord.org)
+			LEFT JOIN actor.usr_standing_penalty ausp 
+				ON ( h.usr = ausp.usr AND ( ausp.stop_date IS NULL OR ausp.stop_date > NOW() ) )
+			LEFT JOIN config.standing_penalty csp
+				ON ( csp.id = ausp.standing_penalty AND csp.block_list LIKE '%CAPTURE%' )
 		  WHERE	a.circ_lib = ?
 		  	AND h.capture_time IS NULL
 		  	AND h.cancel_time IS NULL
 		  	AND (h.expire_time IS NULL OR h.expire_time > NOW())
+			AND csp.id IS NULL
 			$status_filter
 		  ORDER BY CASE WHEN ord.position IS NOT NULL THEN ord.position ELSE 999 END, h.request_time
 		  LIMIT $limit
@@ -520,10 +525,15 @@ sub hold_pull_list {
             SELECT    count(*)
               FROM    $h_table h
                   JOIN $a_table a ON (h.current_copy = a.id)
+                  LEFT JOIN actor.usr_standing_penalty ausp 
+                    ON ( h.usr = ausp.usr AND ( ausp.stop_date IS NULL OR ausp.stop_date > NOW() ) )
+                  LEFT JOIN config.standing_penalty csp
+                    ON ( csp.id = ausp.standing_penalty AND csp.block_list LIKE '%CAPTURE%' )
               WHERE    a.circ_lib = ?
                   AND h.capture_time IS NULL
                   AND h.cancel_time IS NULL
                   AND (h.expire_time IS NULL OR h.expire_time > NOW())
+                  AND csp.id IS NULL
                 $status_filter
         SQL
     }

commit 266fc54ebaab9806af3ee86ba39b778bc192ebf8
Author: Mike Rylander <mrylander at gmail.com>
Date:   Tue Apr 10 10:21:02 2012 -0400

    Avoid checkin capture for CAPTURE-blocked holds
    
    Teach the nearest_hold sub about CAPTURE-blocking penalties
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

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 ada8dc4..78b0596 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
@@ -294,8 +294,8 @@ sub nearest_hold {
 	local $OpenILS::Application::Storage::WRITE = 1;
 
 	my $holdsort = isTrue($fifo) ?
-            "pgt.hold_priority, CASE WHEN h.cut_in_line IS TRUE THEN 0 ELSE 1 END, h.request_time, h.selection_depth DESC, p.prox " :
-            "p.prox, pgt.hold_priority, CASE WHEN h.cut_in_line IS TRUE THEN 0 ELSE 1 END, h.selection_depth DESC, h.request_time ";
+			"pgt.hold_priority, CASE WHEN h.cut_in_line IS TRUE THEN 0 ELSE 1 END, h.request_time, h.selection_depth DESC, p.prox " :
+			"p.prox, pgt.hold_priority, CASE WHEN h.cut_in_line IS TRUE THEN 0 ELSE 1 END, h.selection_depth DESC, h.request_time ";
 
 	my $ids = action::hold_request->db_Main->selectcol_arrayref(<<"	SQL", {}, $here, $cp, $age);
 		SELECT	h.id
@@ -304,12 +304,17 @@ sub nearest_hold {
 		  	JOIN action.hold_copy_map hm ON (hm.hold = h.id)
 		  	JOIN actor.usr au ON (au.id = h.usr)
 		  	JOIN permission.grp_tree pgt ON (au.profile = pgt.id)
+		  	LEFT JOIN actor.usr_standing_penalty ausp
+				ON ( au.id = ausp.usr AND ( ausp.stop_date IS NULL OR ausp.stop_date > NOW() ) )
+		  	LEFT JOIN config.standing_penalty csp
+				ON ( csp.id = ausp.standing_penalty AND csp.block_list LIKE '%CAPTURE%' )
 		  WHERE hm.target_copy = ?
 		  	AND (AGE(NOW(),h.request_time) >= CAST(? AS INTERVAL) OR p.prox = 0)
 			AND h.capture_time IS NULL
 		  	AND h.cancel_time IS NULL
 		  	AND (h.expire_time IS NULL OR h.expire_time > NOW())
-            AND h.frozen IS FALSE
+			AND h.frozen IS FALSE
+		  	AND csp.id IS NULL
 		ORDER BY CASE WHEN h.hold_type IN ('R','F') THEN 0 ELSE 1 END, $holdsort
 		LIMIT $limit
 	SQL

commit a8155fc4c4728adbfd3e734a9ede7eca1f067c78
Author: Bill Erickson <berick at esilibrary.com>
Date:   Tue Apr 10 15:42:17 2012 -0400

    hold CAP/FILL blocks : separate CIRC and FULFILL blocks
    
    This breaks the CIRC standing penalty block out into two separate
    blocks.  The existing CIRC block now prevents circulations on checkouts
    where the checkout is not fulfilling a hold.  A new FULFILL block type
    is added which, when applied to a user, (only) prevents the user from
    checking out items that fulfill a hold.
    
    To always prevents checkouts, use both blocks.  Use individual blocks
    where one or the other behavior is desired.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson 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 f5c0f07..7a30879 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
@@ -542,6 +542,7 @@ my @AUTOLOAD_FIELDS = qw/
     fake_hold_dest
     limit_groups
     override_args
+    checkout_is_for_hold
 /;
 
 
@@ -978,9 +979,9 @@ sub is_group_descendant {
 }
 
 sub check_captured_holds {
-   my $self    = shift;
-   my $copy    = $self->copy;
-   my $patron  = $self->patron;
+    my $self    = shift;
+    my $copy    = $self->copy;
+    my $patron  = $self->patron;
 
     return undef unless $copy;
 
@@ -989,7 +990,7 @@ sub check_captured_holds {
     $logger->info("circulator: copy is on holds shelf, searching for the correct hold");
 
     # Item is on the holds shelf, make sure it's going to the right person
-    my $holds   = $self->editor->search_action_hold_request(
+    my $hold = $self->editor->search_action_hold_request(
         [
             { 
                 current_copy        => $copy->id , 
@@ -999,10 +1000,11 @@ sub check_captured_holds {
             },
             { limit => 1 }
         ]
-    );
+    )->[0];
 
-    if( $holds and $$holds[0] ) {
-        return undef if $$holds[0]->usr == $patron->id;
+    if ($hold and $hold->usr == $patron->id) {
+        $self->checkout_is_for_hold(1);
+        return undef;
     }
 
     $logger->info("circulator: this copy is needed by a different patron to fulfill a hold");
@@ -1097,10 +1099,33 @@ sub run_patron_permit_scripts {
 
         my $results = $self->run_indb_circ_test;
         unless($self->circ_test_success) {
-            # no_item result is OK during noncat checkout
-            unless(@$results == 1 && $results->[0]->{fail_part} eq 'no_item' and $self->is_noncat) {
-                push @allevents, $self->matrix_test_result_events;
+            my @trimmed_results;
+
+            if ($self->is_noncat) {
+                # no_item result is OK during noncat checkout
+                @trimmed_results = grep { ($_->{fail_part} || '') ne 'no_item' } @$results;
+            }
+
+            if ($self->checkout_is_for_hold) {
+                # if this checkout will fulfill a hold, ignore CIRC blocks
+                # and rely instead on the (later-checked) FULFILL block
+
+                my @pen_names = grep {$_} map {$_->{fail_part}} @$results;
+                my $fblock_pens = $self->editor->search_config_standing_penalty(
+                    {name => [@pen_names], block_list => {like => '%CIRC%'}});
+
+                for my $res (@$results) {
+                    my $name = $res->{fail_part} || '';
+                    next if grep {$_->name eq $name} @$fblock_pens or 
+                        ($self->is_noncat and $name eq 'no_item');
+                    push(@trimmed_results, $res);
+                }
             }
+
+            # update the final set of test results
+            $self->matrix_test_result(\@trimmed_results); 
+
+            push @allevents, $self->matrix_test_result_events;
         }
 
     } else {
@@ -1120,6 +1145,8 @@ sub run_patron_permit_scripts {
         $penalties = $penalties->{fatal_penalties};
 
         for my $pen (@$penalties) {
+            # CIRC blocks are ignored if this is a FULFILL scenario
+            next if $mask eq 'CIRC' and $self->checkout_is_for_hold;
             my $event = OpenILS::Event->new($pen->name);
             $event->{desc} = $pen->label;
             push(@allevents, $event);
@@ -1633,6 +1660,44 @@ sub bail_on_events {
     $self->bail_out(1);
 }
 
+# ------------------------------------------------------------------------------
+# A hold FULFILL block is just like a CIRC block, except that FULFILL only
+# affects copies that will fulfill holds and CIRC affects all other copies.
+# If blocks exists, bail, push Events onto the event pile, and return true.
+# ------------------------------------------------------------------------------
+sub check_hold_fulfill_blocks {
+    my $self = shift;
+
+    # See if the user has any penalties applied that prevent hold fulfillment
+    my $pens = $self->editor->json_query({
+        select => {csp => ['name', 'label']},
+        from => {ausp => {csp => {}}},
+        where => {
+            '+ausp' => {
+                usr => $self->patron->id,
+                org_unit => $U->get_org_full_path($self->circ_lib),
+                '-or' => [
+                    {stop_date => undef},
+                    {stop_date => {'>' => 'now'}}
+                ]
+            },
+            '+csp' => {block_list => {'like' => '%FULFILL%'}}
+        }
+    });
+
+    return 0 unless @$pens;
+
+    for my $pen (@$pens) {
+        $logger->info("circulator: patron has hold FULFILL block " . $pen->{name});
+        my $event = OpenILS::Event->new($pen->{name});
+        $event->{desc} = $pen->{label};
+        $self->push_events($event);
+    }
+
+    $self->override_events;
+    return $self->bail_out;
+}
+
 
 # ------------------------------------------------------------------------------
 # When an item is checked out, see if we can fulfill a hold for this patron
@@ -1682,6 +1747,8 @@ sub handle_checkout_holds {
         $logger->info("circulator: found related hold to fulfill in checkout");
     }
 
+    return if $self->check_hold_fulfill_blocks;
+
     $logger->debug("circulator: checkout fulfilling hold " . $hold->id);
 
     # if the hold was never officially captured, capture it.

commit ae0e26ed0862b3694415806ce2dc05e128868c24
Author: Bill Erickson <berick at esilibrary.com>
Date:   Tue Apr 10 15:41:51 2012 -0400

    DB seed data for CAPTURE and FULFILL penalty blocks
    
    All occurrences of HOLD in the block list for any existing penalties are
    updated to HOLD|CAPTURE|FULFILL for backwards compatibility, minus the
    handful of STAFF_* penalties whose codes match their respective
    block_lists.
    
    To use these new block types, simply update existing penalties as
    desired or add new local pentalty types for staff-managed patron
    blocking messages.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    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 312a425..0c0744c 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -20,13 +20,13 @@ INSERT INTO config.standing (id, value) VALUES (2, oils_i18n_gettext(2, 'Barred'
 SELECT SETVAL('config.standing_id_seq'::TEXT, 100);
 
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
-	VALUES (1,'PATRON_EXCEEDS_FINES',oils_i18n_gettext(1, 'Patron exceeds fine threshold', 'csp', 'label'),'CIRC|HOLD|RENEW', TRUE);
+	VALUES (1,'PATRON_EXCEEDS_FINES',oils_i18n_gettext(1, 'Patron exceeds fine threshold', 'csp', 'label'),'CIRC|HOLD|CAPTURE|FULFILL|RENEW', TRUE);
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
-	VALUES (2,'PATRON_EXCEEDS_OVERDUE_COUNT',oils_i18n_gettext(2, 'Patron exceeds max overdue item threshold', 'csp', 'label'),'CIRC|HOLD|RENEW', TRUE);
+	VALUES (2,'PATRON_EXCEEDS_OVERDUE_COUNT',oils_i18n_gettext(2, 'Patron exceeds max overdue item threshold', 'csp', 'label'),'CIRC|HOLD|CAPTURE|FULFILL|RENEW', TRUE);
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
 	VALUES (3,'PATRON_EXCEEDS_CHECKOUT_COUNT',oils_i18n_gettext(3, 'Patron exceeds max checked out item threshold', 'csp', 'label'),'CIRC', TRUE);
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
-	VALUES (4,'PATRON_EXCEEDS_COLLECTIONS_WARNING',oils_i18n_gettext(4, 'Patron exceeds pre-collections warning fine threshold', 'csp', 'label'),'CIRC|HOLD|RENEW', TRUE);
+	VALUES (4,'PATRON_EXCEEDS_COLLECTIONS_WARNING',oils_i18n_gettext(4, 'Patron exceeds pre-collections warning fine threshold', 'csp', 'label'),'CIRC|HOLD|CAPTURE|FULFILL|RENEW', TRUE);
 
 INSERT INTO config.standing_penalty (id,name,label,staff_alert) VALUES (20,'ALERT_NOTE',oils_i18n_gettext(20, 'Alerting Note, no blocks', 'csp', 'label'),TRUE);
 INSERT INTO config.standing_penalty (id,name,label) VALUES (21,'SILENT_NOTE',oils_i18n_gettext(21, 'Note, no blocks', 'csp', 'label'));
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
new file mode 100644
index 0000000..b2c25c3
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.hold_cap_fill_penalty_blocks.sql
@@ -0,0 +1,11 @@
+
+
+UPDATE config.standing_penalty 
+    SET block_list = REPLACE(block_list, 'HOLD', 'HOLD|CAPTURE|FULFILL') 
+    WHERE   
+        -- STAFF_ penalties have names that match their block list
+        name NOT LIKE 'STAFF_%' 
+        -- belt & suspenders, also good for testing
+        AND block_list NOT LIKE '%CAPTURE%' 
+        AND block_list NOT LIKE '%FULFILL%'; 
+

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

Summary of changes:
 Open-ILS/examples/fm_IDL.xml                       |   13 +++
 .../lib/OpenILS/Application/Circ/Circulate.pm      |   92 +++++++++++++++++--
 .../Application/Storage/Publisher/action.pm        |   21 ++++-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |    2 +-
 Open-ILS/src/sql/Pg/110.hold_matrix.sql            |   10 ++-
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |    8 +-
 ... => 0721.data.hold_cap_fill_penalty_blocks.sql} |   37 ++++++--
 7 files changed, 156 insertions(+), 27 deletions(-)
 copy Open-ILS/src/sql/Pg/upgrade/{0668.schema.fix_indb_hold_permit.sql => 0721.data.hold_cap_fill_penalty_blocks.sql} (88%)


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list