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

Evergreen Git git at git.evergreen-ils.org
Wed Jun 5 00:02:53 EDT 2013


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  e103aadbf620e75933a3de80c901a5f91d98f5e8 (commit)
       via  c13dc8a6b5247c89a874ad92ecaa04974409389c (commit)
       via  d4918fa6a9b433b35dcc1c186902a7235fb928fd (commit)
      from  2060027f71755fbdf284470e68acc0bac40cbb15 (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 e103aadbf620e75933a3de80c901a5f91d98f5e8
Author: Ben Shum <bshum at biblio.org>
Date:   Tue Jun 4 23:17:17 2013 -0400

    Move lost items modification release notes
    
    Moved to the Circulation category and small changes to the formatting for
    conversion.
    
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/docs/RELEASE_NOTES_NEXT/lost_items_modifications.txt b/docs/RELEASE_NOTES_NEXT/Circulation/lost_items_modifications.txt
similarity index 78%
rename from docs/RELEASE_NOTES_NEXT/lost_items_modifications.txt
rename to docs/RELEASE_NOTES_NEXT/Circulation/lost_items_modifications.txt
index bd9e47e..3c87593 100644
--- a/docs/RELEASE_NOTES_NEXT/lost_items_modifications.txt
+++ b/docs/RELEASE_NOTES_NEXT/Circulation/lost_items_modifications.txt
@@ -1,5 +1,6 @@
-New feature: "Patron blocking by lost items and include lost as items out."
-==========================================================================
+Patron blocking by lost items and include lost as items out
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 This feature has two main parts, both of which are to improve the staff's
 ability to assist patrons in regards to lost items.
 
@@ -11,4 +12,3 @@ setting is modified through the Group Penalty Thresholds page.
 'Include Lost circulations in lump sum tallies in Patron Display',
 the staff have the ability to determine if lost items will be included
 in items out.
-

commit c13dc8a6b5247c89a874ad92ecaa04974409389c
Author: Ben Shum <bshum at biblio.org>
Date:   Tue Jun 4 23:38:25 2013 -0400

    Stamping upgrade script for lost items blocking
    
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 5a955d4..190ecfc 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -91,7 +91,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 ('0793', :eg_version); -- senator/miker
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0794', :eg_version); -- ktomita/bshum
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql b/Open-ILS/src/sql/Pg/upgrade/0794.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql
similarity index 99%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql
rename to Open-ILS/src/sql/Pg/upgrade/0794.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql
index 22b60fd..a43ea66 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0794.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
-SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('0794', :eg_version);
 
 INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
     VALUES (5,'PATRON_EXCEEDS_LOST_COUNT',oils_i18n_gettext(5, 'Patron exceeds max lost item threshold', 'csp', 'label'),'CIRC|FULFILL|HOLD|CAPTURE|RENEW', TRUE);

commit d4918fa6a9b433b35dcc1c186902a7235fb928fd
Author: Kyle Tomita <ktomita at catalystitservices.com>
Date:   Thu Mar 14 15:01:14 2013 -0700

    Patron Blocking by lost items and include lost as items out
    
    This feature has two main parts, patron blocking by number
    of lost items and include lost items as items out.  A group penalty
    threshold will be added for lost items.  This will restrict patrons
    who have lost too many items. The inclusion of lost items as items
    out will be an optional setting, like claimed returned items. This
    will allow libraries to set what type of item statuses count toward
    the total items out.
    
    Signed-off-by: Kyle Tomita <ktomita at catalystitservices.com>
    Signed-off-by: Justin Douma <jdouma at catalystitservices.com>
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/Open-ILS/src/extras/ils_events.xml b/Open-ILS/src/extras/ils_events.xml
index 84ba694..9706603 100644
--- a/Open-ILS/src/extras/ils_events.xml
+++ b/Open-ILS/src/extras/ils_events.xml
@@ -170,10 +170,9 @@
 	<event code='1235' textcode='INVALID_USER_XACT_ID'>
         <desc xml:lang="en-US">While you were trying to make payments, this account's transaction history changed.  Please go back and try again.</desc>
 	</event>
-
-
-
-
+    <event code='1236' textcode='PATRON_EXCEEDS_LOST_COUNT'>
+        <desc xml:lang="en-US">The patron has too many lost items.</desc>
+    </event>
 	<event code='1500' textcode='ACTION_CIRCULATION_NOT_FOUND'>
 		<desc xml:lang="en-US">
 			Someone attempted to retrieve a circulation object from the system and 
diff --git a/Open-ILS/src/sql/Pg/100.circ_matrix.sql b/Open-ILS/src/sql/Pg/100.circ_matrix.sql
index 3dbb328..643dd4e 100644
--- a/Open-ILS/src/sql/Pg/100.circ_matrix.sql
+++ b/Open-ILS/src/sql/Pg/100.circ_matrix.sql
@@ -648,9 +648,11 @@ DECLARE
     max_fines           permission.grp_penalty_threshold%ROWTYPE;
     max_overdue         permission.grp_penalty_threshold%ROWTYPE;
     max_items_out       permission.grp_penalty_threshold%ROWTYPE;
+    max_lost            permission.grp_penalty_threshold%ROWTYPE;
     tmp_grp             INT;
     items_overdue       INT;
     items_out           INT;
+    items_lost          INT;
     context_org_list    INT[];
     current_fines        NUMERIC(8,2) := 0.0;
     tmp_fines            NUMERIC(8,2);
@@ -831,7 +833,30 @@ BEGIN
                 JOIN  actor.org_unit_full_path( max_items_out.org_unit ) fp ON (circ.circ_lib = fp.id)
           WHERE circ.usr = match_user
                 AND circ.checkin_time IS NULL
-                AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL);
+                AND (circ.stop_fines IN (
+                    SELECT 'MAXFINES'::TEXT
+                    UNION ALL
+                    SELECT 'LONGOVERDUE'::TEXT
+                    UNION ALL
+                    SELECT 'LOST'::TEXT
+                    WHERE 'true' ILIKE
+                    (
+                        SELECT CASE
+                            WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.tally_lost', circ.circ_lib)) ILIKE 'true' THEN 'true'
+                            ELSE 'false'
+                        END
+                    )
+                    UNION ALL
+                    SELECT 'CLAIMSRETURNED'::TEXT
+                    WHERE 'false' ILIKE
+                    (
+                        SELECT CASE
+                            WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.do_not_tally_claims_returned', circ.circ_lib)) ILIKE 'true' THEN 'true'
+                            ELSE 'false'
+                        END
+                    )
+                    ) OR circ.stop_fines IS NULL)
+                AND xact_finish IS NULL;
 
            IF items_out >= max_items_out.threshold::INT THEN
             new_sp_row.usr := match_user;
@@ -841,6 +866,61 @@ BEGIN
            END IF;
     END IF;
 
+    -- Start over for max lost
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many lost items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+
+            SELECT * INTO max_lost FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 5 AND org_unit = tmp_org.id;
+
+            IF max_lost.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_lost.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_lost.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+            FROM  actor.usr_standing_penalty
+            WHERE usr = match_user
+                AND org_unit = max_lost.org_unit
+                AND (stop_date IS NULL or stop_date > NOW())
+                AND standing_penalty = 5;
+
+        SELECT  INTO items_lost COUNT(*)
+        FROM  action.circulation circ
+            JOIN  actor.org_unit_full_path( max_lost.org_unit ) fp ON (circ.circ_lib = fp.id)
+        WHERE circ.usr = match_user
+            AND circ.checkin_time IS NULL
+            AND (circ.stop_fines = 'LOST')
+            AND xact_finish IS NULL;
+
+        IF items_lost >= max_lost.threshold::INT AND 0 < max_lost.threshold::INT THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_lost.org_unit;
+            new_sp_row.standing_penalty := 5;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
     -- Start over for collections warning
     SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
 
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 a8ddf6a..7f401cd 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -27,6 +27,8 @@ 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|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|FULFILL|HOLD|CAPTURE|RENEW', TRUE);
+INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
+	VALUES (5,'PATRON_EXCEEDS_LOST_COUNT',oils_i18n_gettext(5, 'Patron exceeds max lost item 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'));
@@ -1637,6 +1639,8 @@ INSERT INTO permission.grp_penalty_threshold (grp,org_unit,penalty,threshold)
     VALUES (1,1,2,10.0);
 INSERT INTO permission.grp_penalty_threshold (grp,org_unit,penalty,threshold)
     VALUES (1,1,3,10.0);
+INSERT INTO permission.grp_penalty_threshold (grp,org_unit,penalty,threshold)
+    VALUES (1,1,5,10.0);
 
 SELECT SETVAL('permission.grp_penalty_threshold_id_seq'::TEXT, (SELECT MAX(id) FROM permission.grp_penalty_threshold));
 
@@ -2886,6 +2890,19 @@ INSERT into config.org_unit_setting_type
         'coust', 'description'),
     'bool', null)
 
+,('circ.tally_lost', 'circ',
+    oils_i18n_gettext(
+        'circ.tally_lost',
+        'Include Lost circulations in lump sum tallies in Patron Display.',
+        'coust',
+        'label'),
+    oils_i18n_gettext(
+        'circ.tally_lost',
+        'In the Patron Display interface, the number of total active circulations for a given patron is presented in the Summary sidebar and underneath the Items Out navigation button.  This setting will include Lost circulations as counting toward these tallies.',
+        'coust',
+        'description'),
+    'bool', null)
+
 ,( 'circ.grace.extend', 'circ',
     oils_i18n_gettext('circ.grace.extend',
         'Auto-Extend Grace Periods',
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql
new file mode 100644
index 0000000..22b60fd
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql
@@ -0,0 +1,483 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+INSERT INTO config.standing_penalty (id,name,label,block_list,staff_alert)
+    VALUES (5,'PATRON_EXCEEDS_LOST_COUNT',oils_i18n_gettext(5, 'Patron exceeds max lost item threshold', 'csp', 'label'),'CIRC|FULFILL|HOLD|CAPTURE|RENEW', TRUE);
+
+INSERT INTO config.org_unit_setting_type ( name, grp, label, description, datatype ) VALUES (
+    'circ.tally_lost', 'circ',
+    oils_i18n_gettext(
+        'circ.tally_lost',
+        'Include Lost circulations in lump sum tallies in Patron Display.',
+        'coust',
+        'label'),
+    oils_i18n_gettext(
+        'circ.tally_lost',
+        'In the Patron Display interface, the number of total active circulations for a given patron is presented in the Summary sidebar and underneath the Items Out navigation button.  This setting will include Lost circulations as counting toward these tallies.',
+        'coust',
+        'description'),
+    'bool'
+);
+
+-- Function: actor.calculate_system_penalties(integer, integer)
+-- DROP FUNCTION actor.calculate_system_penalties(integer, integer);
+
+CREATE OR REPLACE FUNCTION actor.calculate_system_penalties(match_user integer, context_org integer)
+    RETURNS SETOF actor.usr_standing_penalty AS
+$BODY$
+DECLARE
+    user_object             actor.usr%ROWTYPE;
+    new_sp_row            actor.usr_standing_penalty%ROWTYPE;
+    existing_sp_row       actor.usr_standing_penalty%ROWTYPE;
+    collections_fines      permission.grp_penalty_threshold%ROWTYPE;
+    max_fines               permission.grp_penalty_threshold%ROWTYPE;
+    max_overdue           permission.grp_penalty_threshold%ROWTYPE;
+    max_items_out       permission.grp_penalty_threshold%ROWTYPE;
+    max_lost      		     permission.grp_penalty_threshold%ROWTYPE;
+    tmp_grp                 INT;
+    items_overdue        INT;
+    items_out              INT;
+    items_lost	            INT;
+    context_org_list     INT[];
+    current_fines          NUMERIC(8,2) := 0.0;
+    tmp_fines               NUMERIC(8,2);
+    tmp_groc               RECORD;
+    tmp_circ                RECORD;
+    tmp_org                actor.org_unit%ROWTYPE;
+    tmp_penalty          config.standing_penalty%ROWTYPE;
+    tmp_depth            INTEGER;
+BEGIN
+    SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+
+    -- Max fines
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has a high fine balance
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 1 AND org_unit = tmp_org.id;
+
+            IF max_fines.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_fines.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+              FROM  actor.usr_standing_penalty
+              WHERE usr = match_user
+                    AND org_unit = max_fines.org_unit
+                    AND (stop_date IS NULL or stop_date > NOW())
+                    AND standing_penalty = 1;
+
+        SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+        SELECT  SUM(f.balance_owed) INTO current_fines
+          FROM  money.materialized_billable_xact_summary f
+                JOIN (
+                    SELECT  r.id
+                      FROM  booking.reservation r
+                      WHERE r.usr = match_user
+                            AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND xact_finish IS NULL
+                                UNION ALL
+                    SELECT  g.id
+                      FROM  money.grocery g
+                      WHERE g.usr = match_user
+                            AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+                            AND xact_finish IS NULL
+                                UNION ALL
+                    SELECT  circ.id
+                      FROM  action.circulation circ
+                      WHERE circ.usr = match_user
+                            AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND xact_finish IS NULL ) l USING (id);
+
+        IF current_fines >= max_fines.threshold THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_fines.org_unit;
+            new_sp_row.standing_penalty := 1;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for max overdue
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many overdue items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+
+            SELECT * INTO max_overdue FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 2 AND org_unit = tmp_org.id;
+
+            IF max_overdue.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_overdue.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_overdue.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+              FROM  actor.usr_standing_penalty
+              WHERE usr = match_user
+                    AND org_unit = max_overdue.org_unit
+                    AND (stop_date IS NULL or stop_date > NOW())
+                    AND standing_penalty = 2;
+
+        SELECT  INTO items_overdue COUNT(*)
+          FROM  action.circulation circ
+                JOIN  actor.org_unit_full_path( max_overdue.org_unit ) fp ON (circ.circ_lib = fp.id)
+          WHERE circ.usr = match_user
+            AND circ.checkin_time IS NULL
+            AND circ.due_date < NOW()
+            AND (circ.stop_fines = 'MAXFINES' OR circ.stop_fines IS NULL);
+
+        IF items_overdue >= max_overdue.threshold::INT THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_overdue.org_unit;
+            new_sp_row.standing_penalty := 2;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for max out
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many checked out items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_items_out FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 3 AND org_unit = tmp_org.id;
+
+            IF max_items_out.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_items_out.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    -- Fail if the user has too many items checked out
+    IF max_items_out.threshold IS NOT NULL THEN
+        RETURN QUERY
+            SELECT  *
+            FROM  actor.usr_standing_penalty
+            WHERE usr = match_user
+                AND org_unit = max_items_out.org_unit
+                AND (stop_date IS NULL or stop_date > NOW())
+                AND standing_penalty = 3;
+            SELECT  INTO items_out COUNT(*)
+            FROM  action.circulation circ
+            JOIN  actor.org_unit_full_path( max_items_out.org_unit ) fp ON (circ.circ_lib = fp.id)
+            WHERE circ.usr = match_user
+                AND circ.checkin_time IS NULL
+                AND (circ.stop_fines IN (
+                    SELECT 'MAXFINES'::TEXT
+                    UNION ALL
+                    SELECT 'LONGOVERDUE'::TEXT
+                    UNION ALL
+                    SELECT 'LOST'::TEXT
+                    WHERE 'true' ILIKE
+                    (
+                        SELECT CASE
+                            WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.tally_lost', circ.circ_lib)) ILIKE 'true' THEN 'true'
+                            ELSE 'false'
+                        END
+                    )
+                    UNION ALL
+                    SELECT 'CLAIMSRETURNED'::TEXT
+                    WHERE 'false' ILIKE
+                        (
+                            SELECT CASE
+                            WHEN (SELECT value FROM actor.org_unit_ancestor_setting('circ.do_not_tally_claims_returned', circ.circ_lib)) ILIKE 'true' THEN 'true'
+                            ELSE 'false'
+                            END
+                        )
+                    ) OR circ.stop_fines IS NULL)
+                AND xact_finish IS NULL;
+
+    IF items_out >= max_items_out.threshold::INT THEN
+        new_sp_row.usr := match_user;
+        new_sp_row.org_unit := max_items_out.org_unit;
+        new_sp_row.standing_penalty := 3;
+        RETURN NEXT new_sp_row;
+   END IF;
+END IF;
+
+    -- Start over for max lost
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has too many lost items
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_lost FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 5 AND org_unit = tmp_org.id;
+            IF max_lost.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_lost.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT INTO tmp_org * FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_lost.threshold IS NOT NULL THEN
+        RETURN QUERY
+            SELECT  *
+            FROM  actor.usr_standing_penalty
+            WHERE usr = match_user
+                AND org_unit = max_lost.org_unit
+                AND (stop_date IS NULL or stop_date > NOW())
+                AND standing_penalty = 5;
+
+        SELECT INTO items_lost COUNT(*)
+        FROM  action.circulation circ
+            JOIN  actor.org_unit_full_path( max_lost.org_unit ) fp ON (circ.circ_lib = fp.id)
+            WHERE circ.usr = match_user
+                AND circ.checkin_time IS NULL
+                AND (circ.stop_fines = 'LOST')
+                AND xact_finish IS NULL;
+
+        IF items_lost >= max_lost.threshold::INT AND 0 < max_lost.threshold::INT THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_lost.org_unit;
+            new_sp_row.standing_penalty := 5;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for collections warning
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Fail if the user has a collections-level fine balance
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 4 AND org_unit = tmp_org.id;
+            IF max_fines.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_fines.threshold IS NOT NULL THEN
+
+        RETURN QUERY
+            SELECT  *
+                FROM  actor.usr_standing_penalty
+                WHERE usr = match_user
+                    AND org_unit = max_fines.org_unit
+                    AND (stop_date IS NULL or stop_date > NOW())
+                    AND standing_penalty = 4;
+
+        SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+        SELECT  SUM(f.balance_owed) INTO current_fines
+            FROM  money.materialized_billable_xact_summary f
+                JOIN (
+                    SELECT  r.id
+                        FROM  booking.reservation r
+                        WHERE r.usr = match_user
+                            AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND r.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  g.id
+                        FROM  money.grocery g
+                        WHERE g.usr = match_user
+                            AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+                            AND g.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  circ.id
+                        FROM  action.circulation circ
+                        WHERE circ.usr = match_user
+                            AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND circ.xact_finish IS NULL ) l USING (id);
+
+        IF current_fines >= max_fines.threshold THEN
+            new_sp_row.usr := match_user;
+            new_sp_row.org_unit := max_fines.org_unit;
+            new_sp_row.standing_penalty := 4;
+            RETURN NEXT new_sp_row;
+        END IF;
+    END IF;
+
+    -- Start over for in collections
+    SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+
+    -- Remove the in-collections penalty if the user has paid down enough
+    -- This penalty is different, because this code is not responsible for creating 
+    -- new in-collections penalties, only for removing them
+    LOOP
+        tmp_grp := user_object.profile;
+        LOOP
+            SELECT * INTO max_fines FROM permission.grp_penalty_threshold WHERE grp = tmp_grp AND penalty = 30 AND org_unit = tmp_org.id;
+
+            IF max_fines.threshold IS NULL THEN
+                SELECT parent INTO tmp_grp FROM permission.grp_tree WHERE id = tmp_grp;
+            ELSE
+                EXIT;
+            END IF;
+
+            IF tmp_grp IS NULL THEN
+                EXIT;
+            END IF;
+        END LOOP;
+
+        IF max_fines.threshold IS NOT NULL OR tmp_org.parent_ou IS NULL THEN
+            EXIT;
+        END IF;
+
+        SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+
+    END LOOP;
+
+    IF max_fines.threshold IS NOT NULL THEN
+
+        SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( max_fines.org_unit );
+
+        -- first, see if the user had paid down to the threshold
+        SELECT  SUM(f.balance_owed) INTO current_fines
+          FROM  money.materialized_billable_xact_summary f
+                JOIN (
+                    SELECT  r.id
+                        FROM  booking.reservation r
+                        WHERE r.usr = match_user
+                            AND r.pickup_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND r.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  g.id
+                        FROM  money.grocery g
+                        WHERE g.usr = match_user
+                            AND g.billing_location IN (SELECT * FROM unnest(context_org_list))
+                            AND g.xact_finish IS NULL
+                                UNION ALL
+                    SELECT  circ.id
+                        FROM  action.circulation circ
+                        WHERE circ.usr = match_user
+                            AND circ.circ_lib IN (SELECT * FROM unnest(context_org_list))
+                            AND circ.xact_finish IS NULL ) l USING (id);
+
+        IF current_fines IS NULL OR current_fines <= max_fines.threshold THEN
+            -- patron has paid down enough
+
+            SELECT INTO tmp_penalty * FROM config.standing_penalty WHERE id = 30;
+
+            IF tmp_penalty.org_depth IS NOT NULL THEN
+
+                -- since this code is not responsible for applying the penalty, it can't 
+                -- guarantee the current context org will match the org at which the penalty 
+                --- was applied.  search up the org tree until we hit the configured penalty depth
+                SELECT INTO tmp_org * FROM actor.org_unit WHERE id = context_org;
+                SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+
+                WHILE tmp_depth >= tmp_penalty.org_depth LOOP
+
+                    RETURN QUERY
+                        SELECT  *
+                            FROM  actor.usr_standing_penalty
+                            WHERE usr = match_user
+                                AND org_unit = tmp_org.id
+                                AND (stop_date IS NULL or stop_date > NOW())
+                                AND standing_penalty = 30;
+
+                    IF tmp_org.parent_ou IS NULL THEN
+                        EXIT;
+                    END IF;
+
+                    SELECT * INTO tmp_org FROM actor.org_unit WHERE id = tmp_org.parent_ou;
+                    SELECT INTO tmp_depth depth FROM actor.org_unit_type WHERE id = tmp_org.ou_type;
+                END LOOP;
+
+            ELSE
+
+                -- no penalty depth is defined, look for exact matches
+
+                RETURN QUERY
+                    SELECT  *
+                        FROM  actor.usr_standing_penalty
+                        WHERE usr = match_user
+                            AND org_unit = max_fines.org_unit
+                            AND (stop_date IS NULL or stop_date > NOW())
+                            AND standing_penalty = 30;
+            END IF;
+
+        END IF;
+
+    END IF;
+
+    RETURN;
+END;
+$BODY$
+    LANGUAGE plpgsql VOLATILE
+    COST 100
+    ROWS 1000;
+
+COMMIT;
diff --git a/Open-ILS/web/opac/locale/en-US/lang.dtd b/Open-ILS/web/opac/locale/en-US/lang.dtd
index d52ae78..f2fcb14 100644
--- a/Open-ILS/web/opac/locale/en-US/lang.dtd
+++ b/Open-ILS/web/opac/locale/en-US/lang.dtd
@@ -3242,9 +3242,11 @@
 <!ENTITY staff.patron.display_overlay.see_notes.value "(See Notes)">
 <!ENTITY staff.patron.display_overlay.max_bills.value "(Maximum Bills)">
 <!ENTITY staff.patron.display_overlay.max_overdues.value "(Maximum Overdues)">
+<!ENTITY staff.patron.display_overlay.max_lost.value "(Maximum Lost)">
 <!ENTITY staff.patron.display_overlay.max_checked_out.value "(Maximum Checked Out)">
 <!ENTITY staff.patron.display_overlay.has_bills.value "(Has Bills)">
 <!ENTITY staff.patron.display_overlay.has_overdues.value "(Has Overdues)">
+<!ENTITY staff.patron.display_overlay.has_lost.value "(Has Lost)">
 <!ENTITY staff.patron.display_overlay.invalid_dob.value "(Invalid Date of Birth)">
 <!ENTITY staff.patron.display_overlay.invalid_address.value "(Invalid Address)">
 <!ENTITY staff.patron.display_overlay.invalid_email.value "(Invalid Email)">
diff --git a/Open-ILS/xul/staff_client/server/circ/checkout.js b/Open-ILS/xul/staff_client/server/circ/checkout.js
index ea6afa6..56d5ef8 100644
--- a/Open-ILS/xul/staff_client/server/circ/checkout.js
+++ b/Open-ILS/xul/staff_client/server/circ/checkout.js
@@ -501,6 +501,7 @@ circ.checkout.prototype = {
                             case 1232 /* ITEM_DEPOSIT_REQUIRED */ : 
                             case 1233 /* ITEM_RENTAL_FEE_REQUIRED */ : 
                             case 1234 /* ITEM_DEPOSIT_PAID */ : 
+                            case 1236 /* PATRON_EXCEEDS_LOST_COUNT */ :
                             case 1500 /* ACTION_CIRCULATION_NOT_FOUND */ : 
                             case 7002 /* PATRON_EXCEEDS_CHECKOUT_COUNT */ : 
                             case 7003 /* COPY_CIRC_NOT_ALLOWED */ : 
@@ -673,6 +674,7 @@ circ.checkout.prototype = {
                         1215 /* CIRC_EXCEEDS_COPY_RANGE */,
                         1232 /* ITEM_DEPOSIT_REQUIRED */,
                         1233 /* ITEM_RENTAL_FEE_REQUIRED */,
+                        1236 /* PATRON_EXCEEDS_LOST_COUNT */,
                         7002 /* PATRON_EXCEEDS_CHECKOUT_COUNT */,
                         7003 /* COPY_CIRC_NOT_ALLOWED */,
                         7004 /* COPY_NOT_AVAILABLE */, 
@@ -684,6 +686,7 @@ circ.checkout.prototype = {
                     'report_override_on_events' : [ /* Allow auto-override of Patron overrides only */
                         1212 /* PATRON_EXCEEDS_OVERDUE_COUNT */,
                         1213 /* PATRON_BARRED */,
+                        1236 /* PATRON_EXCEEDS_LOST_COUNT */,
                         7002 /* PATRON_EXCEEDS_CHECKOUT_COUNT */,
                         7013 /* PATRON_EXCEEDS_FINES */
                     ],
@@ -701,6 +704,9 @@ circ.checkout.prototype = {
                         '1233' : function(r) {
                             return document.getElementById('circStrings').getString('staff.circ.checkout.override.item_rental_fee_required.warning');
                         },
+                        '1236' : function(r) {
+                            return document.getElementById('circStrings').getString('staff.circ.checkout.override.will_auto');
+                        },
                         '7002' : function(r) {
                             return document.getElementById('circStrings').getString('staff.circ.checkout.override.will_auto');
                         },
@@ -861,6 +867,9 @@ circ.checkout.prototype = {
                         break;
                         case 1232 /* ITEM_DEPOSIT_REQUIRED */ :
                         case 1233 /* ITEM_RENTAL_FEE_REQUIRED */ :
+                        case 1236 /* PATRON_EXCEEDS_LOST_COUNT */ :
+                            found_handled = true;
+                        break;
                         case 7013 /* PATRON_EXCEEDS_FINES */ :
                             found_handled = true;
                         break;
diff --git a/Open-ILS/xul/staff_client/server/circ/util.js b/Open-ILS/xul/staff_client/server/circ/util.js
index af7442f..4a3b2a4 100644
--- a/Open-ILS/xul/staff_client/server/circ/util.js
+++ b/Open-ILS/xul/staff_client/server/circ/util.js
@@ -3755,6 +3755,7 @@ circ.util.renew_via_barcode = function ( params, async ) {
                         case 1232 /* ITEM_DEPOSIT_REQUIRED */ : break;
                         case 1233 /* ITEM_RENTAL_FEE_REQUIRED */ : break;
                         case 1234 /* ITEM_DEPOSIT_PAID */ : break;
+                        case 1236 /* PATRON_EXCEEDS_LOST_COUNT */ : break;
                         case 1500 /* ACTION_CIRCULATION_NOT_FOUND */ : break;
                         case 1502 /* ASSET_COPY_NOT_FOUND */ : 
                             var mis_scan_msg = document.getElementById('circStrings').getFormattedString('staff.circ.copy_status.status.copy_not_found', [params.barcode]);
@@ -3856,6 +3857,7 @@ circ.util.renew_via_barcode = function ( params, async ) {
                     1232 /* ITEM_DEPOSIT_REQUIRED */,
                     1233 /* ITEM_RENTAL_FEE_REQUIRED */,
                     1234 /* ITEM_DEPOSIT_PAID */,
+                    1236 /* PATRON_EXCEEDS_LOST_COUNT */,
                     7002 /* PATRON_EXCEEDS_CHECKOUT_COUNT */,
                     7003 /* COPY_CIRC_NOT_ALLOWED */,
                     7004 /* COPY_NOT_AVAILABLE */,
@@ -3879,6 +3881,7 @@ circ.util.renew_via_barcode = function ( params, async ) {
                     '1234' : function(r) {
                         return document.getElementById('circStrings').getFormattedString('staff.circ.utils.checkin.override.item_deposit_paid.warning');
                     },
+                    '1236' : function(r) { return document.getElementById('circStrings').getFormattedString('staff.circ.renew.barcode', [params.barcode]); },
                     '7002' : function(r) { return document.getElementById('circStrings').getFormattedString('staff.circ.renew.barcode', [params.barcode]); },
                     '7003' : function(r) { return document.getElementById('circStrings').getFormattedString('staff.circ.renew.barcode', [params.barcode]); },
                     '7004' : function(r) {
diff --git a/Open-ILS/xul/staff_client/server/patron/display.js b/Open-ILS/xul/staff_client/server/patron/display.js
index ffac5d1..4728790 100644
--- a/Open-ILS/xul/staff_client/server/patron/display.js
+++ b/Open-ILS/xul/staff_client/server/patron/display.js
@@ -161,8 +161,11 @@ patron.display.prototype = {
                             removeCSSClass(document.documentElement,'PATRON_HAS_BILLS');
                             removeCSSClass(document.documentElement,'PATRON_HAS_OVERDUES');
                             removeCSSClass(document.documentElement,'PATRON_HAS_NOTES');
+                            removeCSSClass(document.documentElement,'PATRON_HAS_LOST');
+                            removeCSSClass(document.documentElement,'PATRON_HAS_LOST_AND_COUNTED');
                             removeCSSClass(document.documentElement,'PATRON_EXCEEDS_CHECKOUT_COUNT');
                             removeCSSClass(document.documentElement,'PATRON_EXCEEDS_OVERDUE_COUNT');
+                            removeCSSClass(document.documentElement,'PATRON_EXCEEDS_LOST_COUNT');
                             removeCSSClass(document.documentElement,'PATRON_EXCEEDS_FINES');
                             removeCSSClass(document.documentElement,'NO_PENALTIES');
                             removeCSSClass(document.documentElement,'ONE_PENALTY');
diff --git a/Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul b/Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul
index 81fc680..a73aa46 100644
--- a/Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul
+++ b/Open-ILS/xul/staff_client/server/patron/display_horiz_overlay.xul
@@ -29,6 +29,8 @@
         <label class="hideme max_out_indicator" value="&staff.patron.display_overlay.max_checked_out.value;" command="cmd_patron_items"/>
         <label class="hideme bills_indicator" value="&staff.patron.display_overlay.has_bills.value;" command="cmd_patron_bills"/>
         <label class="hideme overdues_indicator" value="&staff.patron.display_overlay.has_overdues.value;" command="cmd_patron_items"/>
+        <label class="hideme max_lost_indicator" value="&staff.patron.display_overlay.max_lost.value;" command="cmd_patron_items"/>
+        <label class="hideme lost_indicator" value="&staff.patron.display_overlay.has_lost.value;" command="cmd_patron_items"/>
         <label class="hideme invalid_dob_indicator" value="&staff.patron.display_overlay.invalid_dob.value;" command="cmd_patron_edit"/>
         <label class="hideme invalid_address_indicator" value="&staff.patron.display_overlay.invalid_address.value;" command="cmd_patron_edit"/>
         <label class="hideme invalid_email_indicator" value="&staff.patron.display_overlay.invalid_email.value;" command="cmd_patron_edit"/>
diff --git a/Open-ILS/xul/staff_client/server/patron/display_overlay.xul b/Open-ILS/xul/staff_client/server/patron/display_overlay.xul
index 1fcaa1e..7437b76 100644
--- a/Open-ILS/xul/staff_client/server/patron/display_overlay.xul
+++ b/Open-ILS/xul/staff_client/server/patron/display_overlay.xul
@@ -29,6 +29,8 @@
         <label class="hideme max_out_indicator" value="&staff.patron.display_overlay.max_checked_out.value;" command="cmd_patron_items"/>
         <label class="hideme bills_indicator" value="&staff.patron.display_overlay.has_bills.value;" command="cmd_patron_bills"/>
         <label class="hideme overdues_indicator" value="&staff.patron.display_overlay.has_overdues.value;" command="cmd_patron_items"/>
+        <label class="hideme max_lost_indicator" value="&staff.patron.display_overlay.max_lost.value;" command="cmd_patron_items"/>
+        <label class="hideme lost_indicator" value="&staff.patron.display_overlay.has_lost.value;" command="cmd_patron_items"/>
         <label class="hideme invalid_dob_indicator" value="&staff.patron.display_overlay.invalid_dob.value;" command="cmd_patron_edit"/>
         <label class="hideme invalid_address_indicator" value="&staff.patron.display_overlay.invalid_address.value;" command="cmd_patron_edit"/>
         <label class="hideme invalid_email_indicator" value="&staff.patron.display_overlay.invalid_email.value;" command="cmd_patron_edit"/>
diff --git a/Open-ILS/xul/staff_client/server/patron/summary.js b/Open-ILS/xul/staff_client/server/patron/summary.js
index e560b64..c6e8543 100644
--- a/Open-ILS/xul/staff_client/server/patron/summary.js
+++ b/Open-ILS/xul/staff_client/server/patron/summary.js
@@ -386,11 +386,13 @@ patron.summary.prototype = {
                                         try {
                                             var robj = req.getResultObject();
                                             var do_not_tally_claims_returned = String( obj.OpenILS.data.hash.aous['circ.do_not_tally_claims_returned'] ) == 'true';
+                                            var do_tally_lost = String( obj.OpenILS.data.hash.aous['circ.tally_lost'] ) == 'true';
                                             util.widgets.set_text(e,
                                                 robj.out
                                                 + robj.overdue
                                                 + (do_not_tally_claims_returned ? 0 : robj.claims_returned)
                                                 + robj.long_overdue
+                                                + (do_tally_lost ? robj.lost : 0)
                                             );
                                             if (e2) util.widgets.set_text(e2, robj.overdue    );
                                             if (e3) util.widgets.set_text(e3, robj.claims_returned    );
@@ -402,6 +404,7 @@ patron.summary.prototype = {
                                                     + robj.overdue
                                                     + (do_not_tally_claims_returned ? 0 : robj.claims_returned)
                                                     + robj.long_overdue
+                                                    + (do_tally_lost ? robj.lost : 0)
                                                 ) 
                                                 /* + ( robj.overdue > 0 ? '*' : '' ) */
                                             );
diff --git a/Open-ILS/xul/staff_client/server/patron/util.js b/Open-ILS/xul/staff_client/server/patron/util.js
index ce41bd6..6849c34 100644
--- a/Open-ILS/xul/staff_client/server/patron/util.js
+++ b/Open-ILS/xul/staff_client/server/patron/util.js
@@ -678,8 +678,11 @@ patron.util.set_penalty_css = function(patron) {
         removeCSSClass(document.documentElement,'PATRON_HAS_BILLS');
         removeCSSClass(document.documentElement,'PATRON_HAS_OVERDUES');
         removeCSSClass(document.documentElement,'PATRON_HAS_NOTES');
+        removeCSSClass(document.documentElement,'PATRON_HAS_LOST');
+        removeCSSClass(document.documentElement,'PATRON_HAS_LOST_AND_COUNTED');
         removeCSSClass(document.documentElement,'PATRON_EXCEEDS_CHECKOUT_COUNT');
         removeCSSClass(document.documentElement,'PATRON_EXCEEDS_OVERDUE_COUNT');
+        removeCSSClass(document.documentElement,'PATRON_EXCEEDS_LOST_COUNT');
         removeCSSClass(document.documentElement,'PATRON_EXCEEDS_FINES');
         removeCSSClass(document.documentElement,'NO_PENALTIES');
         removeCSSClass(document.documentElement,'ONE_PENALTY');
@@ -725,6 +728,16 @@ patron.util.set_penalty_css = function(patron) {
             var notes = req.getResultObject();
             if (notes.length > 0) addCSSClass(document.documentElement,'PATRON_HAS_NOTES');
         });
+        net.simple_request('FM_CIRC_COUNT_RETRIEVE_VIA_USER.authoritative',[ ses(), patron.id() ], function(req) {
+            try {
+                var co = req.getResultObject();
+                if (co.lost > 0) addCSSClass(document.documentElement,'PATRON_HAS_LOST');
+                JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
+                if ((String( data.hash.aous['circ.tally_lost'] ) == 'true') && (co.lost > 0)) addCSSClass(document.documentElement,'PATRON_HAS_LOST_AND_COUNTED');
+            } catch(E) {
+                alert(E);
+            }
+        });
 
         /*
         JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
diff --git a/Open-ILS/xul/staff_client/server/skin/patron_display.css b/Open-ILS/xul/staff_client/server/skin/patron_display.css
index f8cecf0..3a1dd98 100644
--- a/Open-ILS/xul/staff_client/server/skin/patron_display.css
+++ b/Open-ILS/xul/staff_client/server/skin/patron_display.css
@@ -41,6 +41,13 @@ row#row_billing_zip { padding-bottom: 10px; }
 .PATRON_HAS_OVERDUES label.overdues_indicator { display: inline; color: #AA4400; }
 .PATRON_HAS_OVERDUES label#under_items { color: red; }
 
+.PATRON_HAS_LOST .patronNameLarge { border-color: #FFC266; }
+.PATRON_HAS_LOST label.items_lost { color: #AA4400; }
+.PATRON_HAS_LOST label.items_lost.value { }
+.PATRON_HAS_LOST label.lost_indicator { display: inline; color: #AA4400; }
+
+.PATRON_HAS_LOST_AND_COUNTED label#under_items { color: red; }
+
 .PATRON_EXCEEDS_CHECKOUT_COUNT .patronNameLarge { border-color: #C99DFF; }
 .PATRON_EXCEEDS_CHECKOUT_COUNT label.items_out { color: purple; }
 /* .PATRON_EXCEEDS_CHECKOUT_COUNT label.items_out.label { text-decoration: underline; } */
@@ -53,6 +60,11 @@ row#row_billing_zip { padding-bottom: 10px; }
 .PATRON_EXCEEDS_OVERDUE_COUNT label.items_overdue.value { }
 .PATRON_EXCEEDS_OVERDUE_COUNT label.max_overdues_indicator { display: inline; color: purple; }
 
+.PATRON_EXCEEDS_LOST_COUNT .patronNameLarge { border-color: #C99DFF; }
+.PATRON_EXCEEDS_LOST_COUNT label.items_lost { color: purple; }
+.PATRON_EXCEEDS_LOST_COUNT label.items_lost.value { }
+.PATRON_EXCEEDS_LOST_COUNT label.max_lost_indicator { display: inline; color: purple; }
+
 .PATRON_EXCEEDS_FINES .patronNameLarge { border-color: #C99DFF; }
 .PATRON_EXCEEDS_FINES label.bill { color: purple; }
 /* .PATRON_EXCEEDS_FINES label.bill.label { text-decoration: underline; } */
diff --git a/docs/RELEASE_NOTES_NEXT/lost_items_modifications.txt b/docs/RELEASE_NOTES_NEXT/lost_items_modifications.txt
new file mode 100644
index 0000000..bd9e47e
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/lost_items_modifications.txt
@@ -0,0 +1,14 @@
+New feature: "Patron blocking by lost items and include lost as items out."
+==========================================================================
+This feature has two main parts, both of which are to improve the staff's
+ability to assist patrons in regards to lost items.
+
+* Patron blocking by lost items.  This will add a group penalty threshold
+that will alert staff when a patron has too many lost items.  This
+setting is modified through the Group Penalty Thresholds page.
+
+* Include lost items as items out.  Through a new library setting,
+'Include Lost circulations in lump sum tallies in Patron Display',
+the staff have the ability to determine if lost items will be included
+in items out.
+

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

Summary of changes:
 Open-ILS/src/extras/ils_events.xml                 |    7 +-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |    2 +-
 Open-ILS/src/sql/Pg/100.circ_matrix.sql            |   82 ++++-
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |   17 +
 ...t_in_items_out_and_patron_blocking_by_lost.sql} |  388 ++++++++------------
 Open-ILS/web/opac/locale/en-US/lang.dtd            |    2 +
 Open-ILS/xul/staff_client/server/circ/checkout.js  |    9 +
 Open-ILS/xul/staff_client/server/circ/util.js      |    3 +
 Open-ILS/xul/staff_client/server/patron/display.js |    3 +
 .../server/patron/display_horiz_overlay.xul        |    2 +
 .../staff_client/server/patron/display_overlay.xul |    2 +
 Open-ILS/xul/staff_client/server/patron/summary.js |    3 +
 Open-ILS/xul/staff_client/server/patron/util.js    |   13 +
 .../staff_client/server/skin/patron_display.css    |   12 +
 .../Circulation/lost_items_modifications.txt       |   14 +
 15 files changed, 322 insertions(+), 237 deletions(-)
 copy Open-ILS/src/sql/Pg/upgrade/{0449.schema.kill_explode_array_and_use_unnest.sql => 0794.add_option_for_including_lost_in_items_out_and_patron_blocking_by_lost.sql} (56%)
 create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/lost_items_modifications.txt


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list