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

Evergreen Git git at git.evergreen-ils.org
Thu Feb 7 17:41:08 EST 2019


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  6ae2427affb3e6cb8c5f96b2a21530efd6798a70 (commit)
       via  c016af3dd14e9ac7c5a5ec54e9b5339e20e1279a (commit)
       via  be0e7e2cd4139d6e1e3d9a42440cf04296e96dcb (commit)
       via  c7727d4966d63a14419c2a8e9df5cabf11f76ee3 (commit)
      from  43405971832887b5cbe75b6eb2421dd1b09a1baf (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 6ae2427affb3e6cb8c5f96b2a21530efd6798a70
Author: Chris Sharp <csharp at georgialibraries.org>
Date:   Thu Feb 7 17:40:15 2019 -0500

    LP#1715767 - stamping upgrade scripts
    
    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index c9685b5..ad8335b 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -92,7 +92,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 ('1143', :eg_version); -- sandbergja/berick
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1146', :eg_version); -- jeffdavis/csharp
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql b/Open-ILS/src/sql/Pg/upgrade/1144.schema.actor.privacy_waiver.sql
similarity index 88%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql
rename to Open-ILS/src/sql/Pg/upgrade/1144.schema.actor.privacy_waiver.sql
index e79cbec..40d37f0 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1144.schema.actor.privacy_waiver.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
-INSERT INTO config.upgrade_log (version) VALUES ('XXXX');
+INSERT INTO config.upgrade_log (version) VALUES ('1144');
 
 CREATE TABLE actor.usr_privacy_waiver (
     id BIGSERIAL PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.function.privacy_waiver_in_purge_data.sql b/Open-ILS/src/sql/Pg/upgrade/1145.function.privacy_waiver_in_purge_data.sql
similarity index 99%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.function.privacy_waiver_in_purge_data.sql
rename to Open-ILS/src/sql/Pg/upgrade/1145.function.privacy_waiver_in_purge_data.sql
index 7ff376d..2f90d2f 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.function.privacy_waiver_in_purge_data.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1145.function.privacy_waiver_in_purge_data.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
-INSERT INTO config.upgrade_log (version) VALUES ('XXXX');
+INSERT INTO config.upgrade_log (version) VALUES ('1145');
 
 CREATE OR REPLACE FUNCTION actor.usr_purge_data(
 	src_usr  IN INTEGER,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.privacy_waiver.sql b/Open-ILS/src/sql/Pg/upgrade/1146.data.privacy_waiver.sql
similarity index 90%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.data.privacy_waiver.sql
rename to Open-ILS/src/sql/Pg/upgrade/1146.data.privacy_waiver.sql
index ab8a6c2..0645b38 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.privacy_waiver.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1146.data.privacy_waiver.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
-SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('1146', :eg_version);
 
 INSERT INTO config.org_unit_setting_type
     (name, label, description, grp, datatype)

commit c016af3dd14e9ac7c5a5ec54e9b5339e20e1279a
Author: Jeff Davis <jeff.davis at bc.libraries.coop>
Date:   Thu Feb 7 11:38:47 2019 -0800

    LP#1715767: remove privacy waiver entries when purging user data
    
    Signed-off-by: Jeff Davis <jeff.davis at bc.libraries.coop>
    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>

diff --git a/Open-ILS/src/sql/Pg/999.functions.global.sql b/Open-ILS/src/sql/Pg/999.functions.global.sql
index 388d10b..71aba5a 100644
--- a/Open-ILS/src/sql/Pg/999.functions.global.sql
+++ b/Open-ILS/src/sql/Pg/999.functions.global.sql
@@ -480,6 +480,7 @@ BEGIN
 	-- actor.*
 	DELETE FROM actor.card WHERE usr = src_usr;
 	DELETE FROM actor.stat_cat_entry_usr_map WHERE target_usr = src_usr;
+	DELETE FROM actor.usr_privacy_waiver WHERE usr = src_usr;
 
 	-- The following update is intended to avoid transient violations of a foreign
 	-- key constraint, whereby actor.usr_address references itself.  It may not be
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.function.privacy_waiver_in_purge_data.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.function.privacy_waiver_in_purge_data.sql
new file mode 100644
index 0000000..7ff376d
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.function.privacy_waiver_in_purge_data.sql
@@ -0,0 +1,342 @@
+BEGIN;
+
+INSERT INTO config.upgrade_log (version) VALUES ('XXXX');
+
+CREATE OR REPLACE FUNCTION actor.usr_purge_data(
+	src_usr  IN INTEGER,
+	specified_dest_usr IN INTEGER
+) RETURNS VOID AS $$
+DECLARE
+	suffix TEXT;
+	renamable_row RECORD;
+	dest_usr INTEGER;
+BEGIN
+
+	IF specified_dest_usr IS NULL THEN
+		dest_usr := 1; -- Admin user on stock installs
+	ELSE
+		dest_usr := specified_dest_usr;
+	END IF;
+
+	-- acq.*
+	UPDATE acq.fund_allocation SET allocator = dest_usr WHERE allocator = src_usr;
+	UPDATE acq.lineitem SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE acq.lineitem SET editor = dest_usr WHERE editor = src_usr;
+	UPDATE acq.lineitem SET selector = dest_usr WHERE selector = src_usr;
+	UPDATE acq.lineitem_note SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE acq.lineitem_note SET editor = dest_usr WHERE editor = src_usr;
+    UPDATE acq.invoice SET closed_by = dest_usr WHERE closed_by = src_usr;
+	DELETE FROM acq.lineitem_usr_attr_definition WHERE usr = src_usr;
+
+	-- Update with a rename to avoid collisions
+	FOR renamable_row in
+		SELECT id, name
+		FROM   acq.picklist
+		WHERE  owner = src_usr
+	LOOP
+		suffix := ' (' || src_usr || ')';
+		LOOP
+			BEGIN
+				UPDATE  acq.picklist
+				SET     owner = dest_usr, name = name || suffix
+				WHERE   id = renamable_row.id;
+			EXCEPTION WHEN unique_violation THEN
+				suffix := suffix || ' ';
+				CONTINUE;
+			END;
+			EXIT;
+		END LOOP;
+	END LOOP;
+
+	UPDATE acq.picklist SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE acq.picklist SET editor = dest_usr WHERE editor = src_usr;
+	UPDATE acq.po_note SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE acq.po_note SET editor = dest_usr WHERE editor = src_usr;
+	UPDATE acq.purchase_order SET owner = dest_usr WHERE owner = src_usr;
+	UPDATE acq.purchase_order SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE acq.purchase_order SET editor = dest_usr WHERE editor = src_usr;
+	UPDATE acq.claim_event SET creator = dest_usr WHERE creator = src_usr;
+
+	-- action.*
+	DELETE FROM action.circulation WHERE usr = src_usr;
+	UPDATE action.circulation SET circ_staff = dest_usr WHERE circ_staff = src_usr;
+	UPDATE action.circulation SET checkin_staff = dest_usr WHERE checkin_staff = src_usr;
+	UPDATE action.hold_notification SET notify_staff = dest_usr WHERE notify_staff = src_usr;
+	UPDATE action.hold_request SET fulfillment_staff = dest_usr WHERE fulfillment_staff = src_usr;
+	UPDATE action.hold_request SET requestor = dest_usr WHERE requestor = src_usr;
+	DELETE FROM action.hold_request WHERE usr = src_usr;
+	UPDATE action.in_house_use SET staff = dest_usr WHERE staff = src_usr;
+	UPDATE action.non_cat_in_house_use SET staff = dest_usr WHERE staff = src_usr;
+	DELETE FROM action.non_cataloged_circulation WHERE patron = src_usr;
+	UPDATE action.non_cataloged_circulation SET staff = dest_usr WHERE staff = src_usr;
+	DELETE FROM action.survey_response WHERE usr = src_usr;
+	UPDATE action.fieldset SET owner = dest_usr WHERE owner = src_usr;
+	DELETE FROM action.usr_circ_history WHERE usr = src_usr;
+
+	-- actor.*
+	DELETE FROM actor.card WHERE usr = src_usr;
+	DELETE FROM actor.stat_cat_entry_usr_map WHERE target_usr = src_usr;
+	DELETE FROM actor.usr_privacy_waiver WHERE usr = src_usr;
+
+	-- The following update is intended to avoid transient violations of a foreign
+	-- key constraint, whereby actor.usr_address references itself.  It may not be
+	-- necessary, but it does no harm.
+	UPDATE actor.usr_address SET replaces = NULL
+		WHERE usr = src_usr AND replaces IS NOT NULL;
+	DELETE FROM actor.usr_address WHERE usr = src_usr;
+	DELETE FROM actor.usr_note WHERE usr = src_usr;
+	UPDATE actor.usr_note SET creator = dest_usr WHERE creator = src_usr;
+	DELETE FROM actor.usr_org_unit_opt_in WHERE usr = src_usr;
+	UPDATE actor.usr_org_unit_opt_in SET staff = dest_usr WHERE staff = src_usr;
+	DELETE FROM actor.usr_setting WHERE usr = src_usr;
+	DELETE FROM actor.usr_standing_penalty WHERE usr = src_usr;
+	UPDATE actor.usr_standing_penalty SET staff = dest_usr WHERE staff = src_usr;
+
+	-- asset.*
+	UPDATE asset.call_number SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE asset.call_number SET editor = dest_usr WHERE editor = src_usr;
+	UPDATE asset.call_number_note SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE asset.copy SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE asset.copy SET editor = dest_usr WHERE editor = src_usr;
+	UPDATE asset.copy_note SET creator = dest_usr WHERE creator = src_usr;
+
+	-- auditor.*
+	DELETE FROM auditor.actor_usr_address_history WHERE id = src_usr;
+	DELETE FROM auditor.actor_usr_history WHERE id = src_usr;
+	UPDATE auditor.asset_call_number_history SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE auditor.asset_call_number_history SET editor  = dest_usr WHERE editor  = src_usr;
+	UPDATE auditor.asset_copy_history SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE auditor.asset_copy_history SET editor  = dest_usr WHERE editor  = src_usr;
+	UPDATE auditor.biblio_record_entry_history SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE auditor.biblio_record_entry_history SET editor  = dest_usr WHERE editor  = src_usr;
+
+	-- biblio.*
+	UPDATE biblio.record_entry SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE biblio.record_entry SET editor = dest_usr WHERE editor = src_usr;
+	UPDATE biblio.record_note SET creator = dest_usr WHERE creator = src_usr;
+	UPDATE biblio.record_note SET editor = dest_usr WHERE editor = src_usr;
+
+	-- container.*
+	-- Update buckets with a rename to avoid collisions
+	FOR renamable_row in
+		SELECT id, name
+		FROM   container.biblio_record_entry_bucket
+		WHERE  owner = src_usr
+	LOOP
+		suffix := ' (' || src_usr || ')';
+		LOOP
+			BEGIN
+				UPDATE  container.biblio_record_entry_bucket
+				SET     owner = dest_usr, name = name || suffix
+				WHERE   id = renamable_row.id;
+			EXCEPTION WHEN unique_violation THEN
+				suffix := suffix || ' ';
+				CONTINUE;
+			END;
+			EXIT;
+		END LOOP;
+	END LOOP;
+
+	FOR renamable_row in
+		SELECT id, name
+		FROM   container.call_number_bucket
+		WHERE  owner = src_usr
+	LOOP
+		suffix := ' (' || src_usr || ')';
+		LOOP
+			BEGIN
+				UPDATE  container.call_number_bucket
+				SET     owner = dest_usr, name = name || suffix
+				WHERE   id = renamable_row.id;
+			EXCEPTION WHEN unique_violation THEN
+				suffix := suffix || ' ';
+				CONTINUE;
+			END;
+			EXIT;
+		END LOOP;
+	END LOOP;
+
+	FOR renamable_row in
+		SELECT id, name
+		FROM   container.copy_bucket
+		WHERE  owner = src_usr
+	LOOP
+		suffix := ' (' || src_usr || ')';
+		LOOP
+			BEGIN
+				UPDATE  container.copy_bucket
+				SET     owner = dest_usr, name = name || suffix
+				WHERE   id = renamable_row.id;
+			EXCEPTION WHEN unique_violation THEN
+				suffix := suffix || ' ';
+				CONTINUE;
+			END;
+			EXIT;
+		END LOOP;
+	END LOOP;
+
+	FOR renamable_row in
+		SELECT id, name
+		FROM   container.user_bucket
+		WHERE  owner = src_usr
+	LOOP
+		suffix := ' (' || src_usr || ')';
+		LOOP
+			BEGIN
+				UPDATE  container.user_bucket
+				SET     owner = dest_usr, name = name || suffix
+				WHERE   id = renamable_row.id;
+			EXCEPTION WHEN unique_violation THEN
+				suffix := suffix || ' ';
+				CONTINUE;
+			END;
+			EXIT;
+		END LOOP;
+	END LOOP;
+
+	DELETE FROM container.user_bucket_item WHERE target_user = src_usr;
+
+	-- money.*
+	DELETE FROM money.billable_xact WHERE usr = src_usr;
+	DELETE FROM money.collections_tracker WHERE usr = src_usr;
+	UPDATE money.collections_tracker SET collector = dest_usr WHERE collector = src_usr;
+
+	-- permission.*
+	DELETE FROM permission.usr_grp_map WHERE usr = src_usr;
+	DELETE FROM permission.usr_object_perm_map WHERE usr = src_usr;
+	DELETE FROM permission.usr_perm_map WHERE usr = src_usr;
+	DELETE FROM permission.usr_work_ou_map WHERE usr = src_usr;
+
+	-- reporter.*
+	-- Update with a rename to avoid collisions
+	BEGIN
+		FOR renamable_row in
+			SELECT id, name
+			FROM   reporter.output_folder
+			WHERE  owner = src_usr
+		LOOP
+			suffix := ' (' || src_usr || ')';
+			LOOP
+				BEGIN
+					UPDATE  reporter.output_folder
+					SET     owner = dest_usr, name = name || suffix
+					WHERE   id = renamable_row.id;
+				EXCEPTION WHEN unique_violation THEN
+					suffix := suffix || ' ';
+					CONTINUE;
+				END;
+				EXIT;
+			END LOOP;
+		END LOOP;
+	EXCEPTION WHEN undefined_table THEN
+		-- do nothing
+	END;
+
+	BEGIN
+		UPDATE reporter.report SET owner = dest_usr WHERE owner = src_usr;
+	EXCEPTION WHEN undefined_table THEN
+		-- do nothing
+	END;
+
+	-- Update with a rename to avoid collisions
+	BEGIN
+		FOR renamable_row in
+			SELECT id, name
+			FROM   reporter.report_folder
+			WHERE  owner = src_usr
+		LOOP
+			suffix := ' (' || src_usr || ')';
+			LOOP
+				BEGIN
+					UPDATE  reporter.report_folder
+					SET     owner = dest_usr, name = name || suffix
+					WHERE   id = renamable_row.id;
+				EXCEPTION WHEN unique_violation THEN
+					suffix := suffix || ' ';
+					CONTINUE;
+				END;
+				EXIT;
+			END LOOP;
+		END LOOP;
+	EXCEPTION WHEN undefined_table THEN
+		-- do nothing
+	END;
+
+	BEGIN
+		UPDATE reporter.schedule SET runner = dest_usr WHERE runner = src_usr;
+	EXCEPTION WHEN undefined_table THEN
+		-- do nothing
+	END;
+
+	BEGIN
+		UPDATE reporter.template SET owner = dest_usr WHERE owner = src_usr;
+	EXCEPTION WHEN undefined_table THEN
+		-- do nothing
+	END;
+
+	-- Update with a rename to avoid collisions
+	BEGIN
+		FOR renamable_row in
+			SELECT id, name
+			FROM   reporter.template_folder
+			WHERE  owner = src_usr
+		LOOP
+			suffix := ' (' || src_usr || ')';
+			LOOP
+				BEGIN
+					UPDATE  reporter.template_folder
+					SET     owner = dest_usr, name = name || suffix
+					WHERE   id = renamable_row.id;
+				EXCEPTION WHEN unique_violation THEN
+					suffix := suffix || ' ';
+					CONTINUE;
+				END;
+				EXIT;
+			END LOOP;
+		END LOOP;
+	EXCEPTION WHEN undefined_table THEN
+	-- do nothing
+	END;
+
+	-- vandelay.*
+	-- Update with a rename to avoid collisions
+	FOR renamable_row in
+		SELECT id, name
+		FROM   vandelay.queue
+		WHERE  owner = src_usr
+	LOOP
+		suffix := ' (' || src_usr || ')';
+		LOOP
+			BEGIN
+				UPDATE  vandelay.queue
+				SET     owner = dest_usr, name = name || suffix
+				WHERE   id = renamable_row.id;
+			EXCEPTION WHEN unique_violation THEN
+				suffix := suffix || ' ';
+				CONTINUE;
+			END;
+			EXIT;
+		END LOOP;
+	END LOOP;
+
+    UPDATE vandelay.session_tracker SET usr = dest_usr WHERE usr = src_usr;
+
+    -- NULL-ify addresses last so other cleanup (e.g. circ anonymization)
+    -- can access the information before deletion.
+	UPDATE actor.usr SET
+		active = FALSE,
+		card = NULL,
+		mailing_address = NULL,
+		billing_address = NULL
+	WHERE id = src_usr;
+
+END;
+$$ LANGUAGE plpgsql;
+
+COMMENT ON FUNCTION actor.usr_purge_data(INT, INT) IS $$
+Finds rows dependent on a given row in actor.usr and either deletes them
+or reassigns them to a different user.
+$$;
+
+COMMIT;
+

commit be0e7e2cd4139d6e1e3d9a42440cf04296e96dcb
Author: Jeff Davis <jdavis at sitka.bclibraries.ca>
Date:   Mon Nov 19 15:53:00 2018 -0800

    LP#1715767: remove privacy waiver entries when referenced actor.usr rows are deleted
    
    Signed-off-by: Jeff Davis <jdavis at sitka.bclibraries.ca>
    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>

diff --git a/Open-ILS/src/sql/Pg/005.schema.actors.sql b/Open-ILS/src/sql/Pg/005.schema.actors.sql
index c97afd7..0572543 100644
--- a/Open-ILS/src/sql/Pg/005.schema.actors.sql
+++ b/Open-ILS/src/sql/Pg/005.schema.actors.sql
@@ -1267,7 +1267,7 @@ $FUNC$ LANGUAGE PLPGSQL;
 
 CREATE TABLE actor.usr_privacy_waiver (
     id BIGSERIAL PRIMARY KEY,
-    usr BIGINT NOT NULL REFERENCES actor.usr(id) DEFERRABLE INITIALLY DEFERRED,
+    usr BIGINT NOT NULL REFERENCES actor.usr(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
     name TEXT NOT NULL,
     place_holds BOOL DEFAULT FALSE,
     pickup_holds BOOL DEFAULT FALSE,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql
index 6b2b7b8..e79cbec 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql
@@ -4,7 +4,7 @@ INSERT INTO config.upgrade_log (version) VALUES ('XXXX');
 
 CREATE TABLE actor.usr_privacy_waiver (
     id BIGSERIAL PRIMARY KEY,
-    usr BIGINT NOT NULL REFERENCES actor.usr(id) DEFERRABLE INITIALLY DEFERRED,
+    usr BIGINT NOT NULL REFERENCES actor.usr(id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
     name TEXT NOT NULL,
     place_holds BOOL DEFAULT FALSE,
     pickup_holds BOOL DEFAULT FALSE,

commit c7727d4966d63a14419c2a8e9df5cabf11f76ee3
Author: Jeff Davis <jdavis at sitka.bclibraries.ca>
Date:   Wed Feb 7 15:11:18 2018 -0800

    LP#1715767: Allow others to use my account (privacy waiver)
    
    Use case: Jane Doe has a hold ready for pickup but is unable to come
    into the library.  Her husband John Doe goes to the library to pick up
    the hold on her behalf.  His name is listed on Jane's account, so
    library staff know it's okay to check out the book on Jane's account and
    give it to John.
    
    This commit adds a new table which lists the names of people who are
    allowed to place holds, pick up holds, check out items, or view
    borrowing history for a user account.  Staff can add, edit, or remove
    entries via the patron editor in the web client; patrons can do so in My
    Account.  The entries are not linked to other user accounts and they do
    not add any extra functionality.  They are essentially special patron
    notes for circulation staff.
    
    Signed-off-by: Jeff Davis <jdavis at sitka.bclibraries.ca>
    Signed-off-by: Chris Sharp <csharp at georgialibraries.org>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index c66eaad..b8d0eff 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -2320,6 +2320,36 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
             </actions>
         </permacrud>
 	</class>
+	<class id="aupw" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="actor::usr_privacy_waiver" oils_persist:tablename="actor.usr_privacy_waiver" reporter:label="Privacy Waiver">
+		<fields oils_persist:primary="id" oils_persist:sequence="actor.usr_privacy_waiver_id_seq">
+			<field reporter:label="ID" name="id" reporter:datatype="id" />
+			<field reporter:label="User" name="usr" reporter:datatype="link" />
+			<field reporter:label="Name" name="name" reporter:datatype="text"/>
+			<field reporter:label="Place Holds?" name="place_holds" reporter:datatype="bool" />
+			<field reporter:label="Pick Up Holds?" name="pickup_holds" reporter:datatype="bool" />
+			<field reporter:label="View Borrowing History?" name="view_history" reporter:datatype="bool" />
+			<field reporter:label="Check Out Items?" name="checkout_items" reporter:datatype="bool" />
+		</fields>
+		<links>
+			<link field="usr" reltype="has_a" key="id" map="" class="au"/>
+		</links>
+		<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+			<actions>
+				<create permission="UPDATE_USER">
+					<context link="usr" field="home_ou"/>
+				</create>
+				<retrieve permission="VIEW_USER">
+					<context link="usr" field="home_ou"/>
+				</retrieve>
+				<update permission="UPDATE_USER">
+					<context link="usr" field="home_ou"/>
+				</update>
+				<delete permission="UPDATE_USER">
+					<context link="usr" field="home_ou"/>
+				</delete>
+			</actions>
+		</permacrud>
+	</class>
 	<class id="aupr" controller="open-ils.cstore" oils_obj:fieldmapper="actor::usr_password_reset" oils_persist:tablename="actor.usr_password_reset" reporter:label="User password reset requests">
 		<fields oils_persist:primary="id" oils_persist:sequence="actor.usr_password_reset_id_seq">
 			<field reporter:label="Request ID" name="id" reporter:datatype="id"/>
@@ -3601,6 +3631,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="Standing Penalties" name="standing_penalties" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="Statistical Category Entries" name="stat_cat_entries" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="Survey Responses" name="survey_responses" oils_persist:virtual="true" reporter:datatype="link"/>
+			<field reporter:label="Privacy Waiver Entries" name = "waiver_entries" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="Workstation Org Unit" name="ws_ou" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="Workstation ID" name="wsid" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="Active" name="active" reporter:datatype="bool"/>
@@ -3676,6 +3707,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<link field="card" reltype="has_a" key="id" map="" class="ac"/>
 			<link field="ident_type2" reltype="has_a" key="id" map="" class="cit"/>
 			<link field="stat_cat_entries" reltype="has_many" key="target_usr" map="" class="actscecm"/>
+			<link field="waiver_entries" reltype="has_many" key="usr" map="" class="aupw"/>
 			<link field="groups" reltype="has_many" key="usr" map="grp" class="pugm"/>
 			<link field="usrgroup" reltype="has_many" key="usrgroup" map="" class="au"/>
 			<link field="checkouts" reltype="has_many" key="usr" map="" class="circ"/>
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
index c2b701a..219f611 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
@@ -115,6 +115,78 @@ sub update_user_setting {
 
 
 __PACKAGE__->register_method(
+    method    => "update_privacy_waiver",
+    api_name  => "open-ils.actor.patron.privacy_waiver.update",
+    signature => {
+        desc => "Replaces any existing privacy waiver entries for the patron with the supplied values.",
+        params => [
+            {desc => 'Authentication token', type => 'string'},
+            {desc => 'User ID', type => 'number'},
+            {desc => 'Arrayref of privacy waiver entries', type => 'object'}
+        ],
+        return => {desc => '1 on success, Event on error'}
+    }
+);
+sub update_privacy_waiver {
+    my($self, $conn, $auth, $user_id, $waiver) = @_;
+    my $e = new_editor(xact => 1, authtoken => $auth);
+    return $e->die_event unless $e->checkauth;
+
+    $user_id = $e->requestor->id unless defined $user_id;
+
+    unless($e->requestor->id == $user_id) {
+        my $user = $e->retrieve_actor_user($user_id) or return $e->die_event;
+        return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
+    }
+
+    foreach my $w (@$waiver) {
+        $w->{usr} = $user_id unless $w->{usr};
+        if ($w->{id} && $w->{id} ne 'new') {
+            my $existing_rows = $e->search_actor_usr_privacy_waiver({usr => $user_id, id => $w->{id}});
+            if ($existing_rows) {
+                my $existing = $existing_rows->[0];
+                # delete existing if name is empty
+                if (!$w->{name} or $w->{name} =~ /^\s*$/) {
+                    $e->delete_actor_usr_privacy_waiver($existing) or return $e->die_event;
+
+                # delete existing if none of the boxes were checked
+                } elsif (!$w->{place_holds} && !$w->{pickup_holds} && !$w->{checkout_items} && !$w->{view_history}) {
+                    $e->delete_actor_usr_privacy_waiver($existing) or return $e->die_event;
+
+                # otherwise, update existing waiver entry
+                } else {
+                    $existing->name($w->{name});
+                    $existing->place_holds($w->{place_holds});
+                    $existing->pickup_holds($w->{pickup_holds});
+                    $existing->checkout_items($w->{checkout_items});
+                    $existing->view_history($w->{view_history});
+                    $e->update_actor_usr_privacy_waiver($existing) or return $e->die_event;
+                }
+            } else {
+                $logger->warn("No privacy waiver entry found for user $user_id with ID " . $w->{id});
+            }
+
+        } else {
+            # ignore new entries with empty name or with no boxes checked
+            next if (!$w->{name} or $w->{name} =~ /^\s*$/);
+            next if (!$w->{place_holds} && !$w->{pickup_holds} && !$w->{checkout_items} && !$w->{view_history});
+            my $new = Fieldmapper::actor::usr_privacy_waiver->new;
+            $new->usr($w->{usr});
+            $new->name($w->{name});
+            $new->place_holds($w->{place_holds});
+            $new->pickup_holds($w->{pickup_holds});
+            $new->checkout_items($w->{checkout_items});
+            $new->view_history($w->{view_history});
+            $e->create_actor_usr_privacy_waiver($new) or return $e->die_event;
+        }
+    }
+
+    $e->commit;
+    return 1;
+}
+
+
+__PACKAGE__->register_method(
     method    => "set_ou_settings",
     api_name  => "open-ils.actor.org_unit.settings.update",
     signature => {
@@ -444,6 +516,9 @@ sub update_patron {
     ( $new_patron, $evt ) = _add_update_cards($e, $patron, $new_patron);
     return $evt if $evt;
 
+    ( $new_patron, $evt ) = _add_update_waiver_entries($e, $patron, $new_patron);
+    return $evt if $evt;
+
     ( $new_patron, $evt ) = _add_survey_responses($e, $patron, $new_patron);
     return $evt if $evt;
 
@@ -540,6 +615,7 @@ sub flesh_user {
         "billing_address",
         "mailing_address",
         "stat_cat_entries",
+        "waiver_entries",
         "settings",
         "usr_activity"
     ];
@@ -568,6 +644,7 @@ sub _clone_patron {
     $new_patron->clear_ischanged();
     $new_patron->clear_isdeleted();
     $new_patron->clear_stat_cat_entries();
+    $new_patron->clear_waiver_entries();
     $new_patron->clear_permissions();
     $new_patron->clear_standing_penalties();
 
@@ -888,6 +965,32 @@ sub _update_card {
 }
 
 
+sub _add_update_waiver_entries {
+    my $e = shift;
+    my $patron = shift;
+    my $new_patron = shift;
+    my $evt;
+
+    my $waiver_entries = $patron->waiver_entries();
+    for my $waiver (@$waiver_entries) {
+        next unless ref $waiver;
+        $waiver->usr($new_patron->id());
+        if ($waiver->isnew()) {
+            next if (!$waiver->name() or $waiver->name() =~ /^\s*$/);
+            next if (!$waiver->place_holds() && !$waiver->pickup_holds() && !$waiver->checkout_items() && !$waiver->view_history());
+            $logger->info("Adding new patron waiver entry");
+            $waiver->clear_id();
+            $e->create_actor_usr_privacy_waiver($waiver) or return (undef, $e->die_event);
+        } elsif ($waiver->ischanged()) {
+            $logger->info("Updating patron waiver entry " . $waiver->id);
+            $e->update_actor_usr_privacy_waiver($waiver) or return (undef, $e->die_event);
+        } elsif ($waiver->isdeleted()) {
+            $logger->info("Deleting patron waiver entry " . $waiver->id);
+            $e->delete_actor_usr_privacy_waiver($waiver) or return (undef, $e->die_event);
+        }
+    }
+    return ($new_patron, undef);
+}
 
 
 # returns event on error.  returns undef otherwise
@@ -3007,6 +3110,7 @@ sub user_retrieve_fleshed_by_id {
         "billing_address",
         "mailing_address",
         "stat_cat_entries",
+        "waiver_entries",
         "usr_activity" ];
     return new_flesh_user($user_id, $fields, $e);
 }
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
index d78b59b..19e8fbc 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
@@ -34,7 +34,7 @@ sub prepare_extended_user_info {
         {
             flesh => 1,
             flesh_fields => {
-                au => [qw/card home_ou addresses ident_type billing_address/, @extra_flesh]
+                au => [qw/card home_ou addresses ident_type billing_address waiver_entries/, @extra_flesh]
                 # ...
             }
         }
@@ -603,6 +603,9 @@ sub load_myopac_prefs_settings {
         }
     }
 
+    my $use_privacy_waiver = $self->ctx->{get_org_setting}->(
+        $e->requestor->home_ou, 'circ.privacy_waiver');
+
     return Apache2::Const::OK
         unless $self->cgi->request_method eq 'POST';
 
@@ -699,8 +702,52 @@ sub load_myopac_prefs_settings {
         'open-ils.actor.patron.settings.update',
         $self->editor->authtoken, undef, \%settings);
 
-    # re-fetch user prefs
     $self->ctx->{updated_user_settings} = \%settings;
+
+    if ($use_privacy_waiver) {
+        my %waiver;
+        my $saved_entries = ();
+        my @waiver_types = qw/place_holds pickup_holds checkout_items view_history/;
+
+        # initialize our waiver hash with waiver IDs from hidden input
+        # (this ensures that we capture entries with no checked boxes)
+        foreach my $waiver_row_id ($self->cgi->param("waiver_id")) {
+            $waiver{$waiver_row_id} = {};
+        }
+
+        # process our waiver checkboxes into a hash, keyed by waiver ID
+        # (a new entry, if any, has id = 'new')
+        foreach my $waiver_type (@waiver_types) {
+            if ($self->cgi->param("waiver_$waiver_type")) {
+                foreach my $waiver_id ($self->cgi->param("waiver_$waiver_type")) {
+                    # ensure this waiver exists in our hash
+                    $waiver{$waiver_id} = {} if !$waiver{$waiver_id};
+                    $waiver{$waiver_id}->{$waiver_type} = 1;
+                }
+            }
+        }
+
+        foreach my $k (keys %waiver) {
+            my $w = $waiver{$k};
+            # get name from textbox
+            $w->{name} = $self->cgi->param("waiver_name_$k");
+            $w->{id} = $k;
+            foreach (@waiver_types) {
+                $w->{$_} = 0 unless ($w->{$_});
+            }
+            push @$saved_entries, $w;
+        }
+
+        # update patron privacy waiver entries
+        $U->simplereq(
+            'open-ils.actor',
+            'open-ils.actor.patron.privacy_waiver.update',
+            $self->editor->authtoken, undef, $saved_entries);
+
+        $self->ctx->{updated_waiver_entries} = $saved_entries;
+    }
+
+    # re-fetch user prefs
     return $self->_load_user_with_prefs || Apache2::Const::OK;
 }
 
diff --git a/Open-ILS/src/sql/Pg/005.schema.actors.sql b/Open-ILS/src/sql/Pg/005.schema.actors.sql
index c387967..c97afd7 100644
--- a/Open-ILS/src/sql/Pg/005.schema.actors.sql
+++ b/Open-ILS/src/sql/Pg/005.schema.actors.sql
@@ -1265,5 +1265,15 @@ BEGIN
 END;
 $FUNC$ LANGUAGE PLPGSQL;
 
+CREATE TABLE actor.usr_privacy_waiver (
+    id BIGSERIAL PRIMARY KEY,
+    usr BIGINT NOT NULL REFERENCES actor.usr(id) DEFERRABLE INITIALLY DEFERRED,
+    name TEXT NOT NULL,
+    place_holds BOOL DEFAULT FALSE,
+    pickup_holds BOOL DEFAULT FALSE,
+    view_history BOOL DEFAULT FALSE,
+    checkout_items BOOL DEFAULT FALSE
+);
+CREATE INDEX actor_usr_privacy_waiver_usr_idx ON actor.usr_privacy_waiver (usr);
 
 COMMIT;
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 649ced5..1fe0bb6 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -19495,3 +19495,18 @@ VALUES (
 
 
 
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype)
+    VALUES (
+        'circ.privacy_waiver',
+        oils_i18n_gettext('circ.privacy_waiver',
+            'Allow others to use patron account (privacy waiver)',
+            'coust', 'label'),
+        oils_i18n_gettext('circ.privacy_waiver',
+            'Add a note to a user account indicating that specified people are allowed to ' ||
+            'place holds, pick up holds, check out items, or view borrowing history for that user account',
+            'coust', 'description'),
+        'circ',
+        'bool'
+    );
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.privacy_waiver.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.privacy_waiver.sql
new file mode 100644
index 0000000..ab8a6c2
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.privacy_waiver.sql
@@ -0,0 +1,21 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype)
+    VALUES (
+        'circ.privacy_waiver',
+        oils_i18n_gettext('circ.privacy_waiver',
+            'Allow others to use patron account (privacy waiver)',
+            'coust', 'label'),
+        oils_i18n_gettext('circ.privacy_waiver',
+            'Add a note to a user account indicating that specified people are allowed to ' ||
+            'place holds, pick up holds, check out items, or view borrowing history for that user account',
+            'coust', 'description'),
+        'circ',
+        'bool'
+    );
+
+COMMIT;
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql
new file mode 100644
index 0000000..6b2b7b8
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.actor.privacy_waiver.sql
@@ -0,0 +1,17 @@
+BEGIN;
+
+INSERT INTO config.upgrade_log (version) VALUES ('XXXX');
+
+CREATE TABLE actor.usr_privacy_waiver (
+    id BIGSERIAL PRIMARY KEY,
+    usr BIGINT NOT NULL REFERENCES actor.usr(id) DEFERRABLE INITIALLY DEFERRED,
+    name TEXT NOT NULL,
+    place_holds BOOL DEFAULT FALSE,
+    pickup_holds BOOL DEFAULT FALSE,
+    view_history BOOL DEFAULT FALSE,
+    checkout_items BOOL DEFAULT FALSE
+);
+CREATE INDEX actor_usr_privacy_waiver_usr_idx ON actor.usr_privacy_waiver (usr);
+
+COMMIT;
+
diff --git a/Open-ILS/src/templates/opac/myopac/prefs_settings.tt2 b/Open-ILS/src/templates/opac/myopac/prefs_settings.tt2
index 415dcec..70f76a9 100644
--- a/Open-ILS/src/templates/opac/myopac/prefs_settings.tt2
+++ b/Open-ILS/src/templates/opac/myopac/prefs_settings.tt2
@@ -23,7 +23,7 @@
                   <input type='hidden' name='history_delete_confirmed' value='1'/>
                   <input type="submit" value="[% l('Confirm') %]" class="opac-button"/>
                 </td></tr>
-                [% ELSIF ctx.updated_user_settings %]
+                [% ELSIF ctx.updated_user_settings OR ctx.updated_waiver_entries %]
                 <tr><td colspan='2'>
                     <div class='renew-summary'>
                         [% l('Account Successfully Updated') %]
@@ -120,6 +120,48 @@
                 </tr>
                 [% END %]
 
+                [%- IF ctx.get_org_setting(ctx.user.home_ou.id, 'circ.privacy_waiver'); %]
+                <tr>
+                    <td>[% l('Allow others to use my account') %]</td>
+                    <td>
+                        [% FOR waiver IN ctx.user.waiver_entries %]
+                        <div id="waiver_[% waiver.id %]">
+                            <input type="hidden" name="waiver_id" value="[% waiver.id %]"/>
+                            [% l('Name:') %] <input type="textbox" name="waiver_name_[% waiver.id %]" value="[% waiver.name | html %]"/><br/>
+                            <label>
+                                <input type="checkbox" name="waiver_place_holds" 
+                                    value="[% waiver.id %]" [% waiver.place_holds == 't' ? 'checked="checked"' : '' %]/>
+                                [% l('Place Holds') %]
+                            </label>
+                            <label>
+                                <input type="checkbox" name="waiver_pickup_holds"
+                                    value="[% waiver.id %]" [% waiver.pickup_holds == 't' ? 'checked="checked"' : '' %]/>
+                                [% l('Pick Up Holds') %]
+                            </label>
+                            <label>
+                                <input type="checkbox" name="waiver_checkout_items"
+                                    value="[% waiver.id %]" [% waiver.checkout_items == 't' ? 'checked="checked"' : '' %]/>
+                                [% l('Check Out Items') %]
+                            </label>
+                            <label>
+                                <input type="checkbox" name="waiver_view_history"
+                                    value="[% waiver.id %]" [% waiver.view_history == 't' ? 'checked="checked"' : '' %]/>
+                                [% l('View Borrowing History') %]
+                            </label>
+                        </div>
+                        [% END %]
+                        <br/>
+                        <div>
+                            [% l('Name:') %] <input type="textbox" name="waiver_name_new"/><br/>
+                            <label><input type="checkbox" name="waiver_place_holds" value="new"/>[% l('Place Holds') %]</label>
+                            <label><input type="checkbox" name="waiver_pickup_holds" value="new"/>[% l('Pick Up Holds') %]</label>
+                            <label><input type="checkbox" name="waiver_checkout_items" value="new"/>[% l('Check Out Items') %]</label>
+                            <label><input type="checkbox" name="waiver_view_history" value="new"/>[% l('View Borrowing History') %]</label>
+                        </div>
+                    </td>
+                </tr>
+                [% END %]
+
                 <!--
                 <tr>
                     <td><label for='prefs_def_font'>[% l("Default Font Size") %]</label></td>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_edit.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_edit.tt2
index 05e0d94..f61f5ee 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_edit.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_edit.tt2
@@ -803,6 +803,55 @@ within the "form" by name for validation.
   </div>
 </div>
 
+<div class="row reg-field-row" ng-if="org_settings['circ.privacy_waiver']">
+  <div class="col-md-3 reg-field-label">
+    <label>[% l('Allow others to use my account') %]</label>
+  </div>
+  <div class="col-md-3 reg-field-input">
+    <div class="row" ng-repeat="waiver_entry in patron.waiver_entries" ng-hide="waiver_entry.isdeleted">
+      <div class="row flex-row">
+        <div class="flex-cell">
+          <input ng-change="field_modified()"
+            type='text' ng-model="waiver_entry.name"/>
+        </div>
+        <div class="flex-cell">
+          <button type="button" 
+            ng-click="field_modified();delete_waiver_entry(waiver_entry)" 
+            class="btn btn-danger">[% l('X') %]</button>
+        </div>
+      </div>
+      <div class="row flex-row reg-field-input">
+        <div class="flex-cell">
+          <label><input ng-change="field_modified()"
+            type='checkbox' ng-model="waiver_entry.place_holds"/>
+            [% l('Place Holds?') %]</label>
+        </div>
+        <div class="flex-cell">
+          <label><input ng-change="field_modified()"
+            type='checkbox' ng-model="waiver_entry.pickup_holds"/>
+            [% l('Pick Up Holds?') %]</label>
+        </div>
+        <div class="flex-cell">
+          <label><input ng-change="field_modified()"
+            type='checkbox' ng-model="waiver_entry.view_history"/>
+            [% l('View Borrowing History?') %]</label>
+        </div>
+        <div class="flex-cell">
+          <label><input ng-change="field_modified()"
+            type='checkbox' ng-model="waiver_entry.checkout_items"/>
+            [% l('Check Out Items?') %]</label>
+        </div>
+      </div> <!-- end checkboxes -->
+    </div> <!-- end ng-repeat waiver_entry -->
+    <div class="row">
+      <div class="col-md-3 reg-field-input">
+      <button type="button" ng-click="new_waiver_entry()" 
+        class="btn btn-success">[% l('Add Person') %]</button>
+      </div>
+    </div>
+  </div> <!-- end waiver entries input -->
+</div> <!-- end waiver entries row -->
+
 </div> <!-- end offline test -->
 
 <!-- addresses -->
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2
index 11cf06a..7963ca0 100644
--- a/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2
+++ b/Open-ILS/src/templates/staff/circ/patron/t_summary.tt2
@@ -177,6 +177,20 @@
       <div class="col-md-5">[% l('Name Keywords') %]</div>
       <div class="col-md-7">{{patron().name_keywords()}}</div>
     </div>
+    <div class="row patron-summary-divider" ng-if="patron().waiver_entries().length > 0">
+      [% l('Allow others to use my account') %]
+    </div>
+    <div class="row" ng-repeat="waiver in patron().waiver_entries()">
+      <div class="col-md-5">{{waiver.name()}}</div>
+      <div class="col-md-7">
+        <ul>
+          <li ng-show="waiver.place_holds() == 't'">[% l('Place holds') %]</li>
+          <li ng-show="waiver.pickup_holds() == 't'">[% l('Pick up holds') %]</li>
+          <li ng-show="waiver.view_history() == 't'">[% l('View borrowing history') %]</li>
+          <li ng-show="waiver.checkout_items() == 't'">[% l('Check out items') %]</li>
+        </ul>
+      </div>
+    </div>
   </div>
 
   <div class="row" ng-repeat="addr in patron().addresses()">
diff --git a/Open-ILS/web/js/ui/default/staff/circ/patron/regctl.js b/Open-ILS/web/js/ui/default/staff/circ/patron/regctl.js
index 4e2e9a2..e33933a 100644
--- a/Open-ILS/web/js/ui/default/staff/circ/patron/regctl.js
+++ b/Open-ILS/web/js/ui/default/staff/circ/patron/regctl.js
@@ -334,6 +334,7 @@ angular.module('egCoreMod')
             'ui.patron.registration.require_address',
             'circ.holds.behind_desk_pickup_supported',
             'circ.patron_edit.clone.copy_address',
+            'circ.privacy_waiver',
             'ui.patron.edit.au.prefix.require',
             'ui.patron.edit.au.prefix.show',
             'ui.patron.edit.au.prefix.suggest',
@@ -726,6 +727,13 @@ angular.module('egCoreMod')
         addr.pending = addr.pending === 't';
     }
 
+    service.ingest_waiver_entry = function(patron, waiver_entry) {
+        waiver_entry.place_holds = waiver_entry.place_holds == 't';
+        waiver_entry.pickup_holds = waiver_entry.pickup_holds == 't';
+        waiver_entry.view_history = waiver_entry.view_history == 't';
+        waiver_entry.checkout_items = waiver_entry.checkout_items == 't';
+    }
+
     /*
      * Existing patron objects reqire some data munging before insertion
      * into the scope.
@@ -773,6 +781,9 @@ angular.module('egCoreMod')
             }
         });
 
+        angular.forEach(patron.waiver_entries,
+            function(waiver_entry) { service.ingest_waiver_entry(patron, waiver_entry) });
+
         service.get_linked_addr_users(patron.addresses);
 
         // Remove stat cat entries that link to out-of-scope stat
@@ -824,6 +835,7 @@ angular.module('egCoreMod')
             cards : [card],
             home_ou : egCore.org.get(egCore.auth.user().ws_ou()),
             stat_cat_entries : [],
+            waiver_entries : [],
             groups : [],
             addresses : [addr]
         };
@@ -1137,6 +1149,15 @@ angular.module('egCoreMod')
             patron.stat_cat_entries().push(newmap);
         });
 
+        var waiver_hashes = patron.waiver_entries();
+        patron.waiver_entries([]);
+        angular.forEach(waiver_hashes, function(waiver_hash) {
+            if (!waiver_hash.isnew && !waiver_hash.isdeleted)
+                waiver_hash.ischanged = true;
+            var waiver_entry = egCore.idl.fromHash('aupw', waiver_hash);
+            patron.waiver_entries().push(waiver_entry);
+        });
+
         if (!patron.isnew()) patron.ischanged(true);
 
         return egCore.net.request(
@@ -1634,6 +1655,24 @@ function($scope , $routeParams , $q , $uibModal , $window , egCore ,
         });
     }
 
+    $scope.new_waiver_entry = function() {
+        var waiver = egCore.idl.toHash(new egCore.idl.aupw());
+        patronRegSvc.ingest_waiver_entry($scope.patron, waiver);
+        waiver.id = patronRegSvc.virt_id--;
+        waiver.isnew = true;
+        $scope.patron.waiver_entries.push(waiver);
+    }
+
+    deleted_waiver_entries = [];
+    $scope.delete_waiver_entry = function(waiver_entry) {
+        if (waiver_entry.id > 0) {
+            waiver_entry.isdeleted = true;
+            deleted_waiver_entries.push(waiver_entry);
+        }
+        var index = $scope.patron.waiver_entries.indexOf(waiver_entry);
+        $scope.patron.waiver_entries.splice(index, 1);
+    }
+
     $scope.replace_card = function() {
         $scope.patron.card.active = false;
         $scope.patron.card.ischanged = true;
@@ -2059,6 +2098,10 @@ function($scope , $routeParams , $q , $uibModal , $window , egCore ,
         $scope.patron.addresses = 
             $scope.patron.addresses.concat(deleted_addresses);
         
+        // ditto for waiver entries
+        $scope.patron.waiver_entries = 
+            $scope.patron.waiver_entries.concat(deleted_waiver_entries);
+
         compress_hold_notify();
 
         var updated_user;
diff --git a/Open-ILS/web/js/ui/default/staff/services/user.js b/Open-ILS/web/js/ui/default/staff/services/user.js
index ccd1d0a..80b2838 100644
--- a/Open-ILS/web/js/ui/default/staff/services/user.js
+++ b/Open-ILS/web/js/ui/default/staff/services/user.js
@@ -17,6 +17,7 @@ function($q,  $timeout,  egNet,  egAuth,  egOrg) {
             'billing_address',                                                     
             'mailing_address',                                                     
             'stat_cat_entries',                                                    
+            'waiver_entries',
             'usr_activity',
             'notes'
         ]
diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/privacy_waiver.adoc b/docs/RELEASE_NOTES_NEXT/Circulation/privacy_waiver.adoc
new file mode 100644
index 0000000..d59f652
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Circulation/privacy_waiver.adoc
@@ -0,0 +1,15 @@
+Allow Others to Use My Account (Privacy Waiver)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Patrons who wish to authorize other people to use their account may
+now do so via My Account.  In the Search and History Preferences tab
+under Account Preferences, a new section labeled "Allow others to use
+my account" allows patrons to enter a name and indicate that the
+specified person is allowed to place holds, pickup holds, view
+borrowing history, or check out items on their account.  This
+information is displayed to circulation staff in the patron account
+summary in the web client.  (Staff may also add, edit, and remove
+entries via the patron editor.)
+
+A new library setting, "Allow others to use patron account (privacy
+waiver)," is used to enable or disable this feature.
+

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

Summary of changes:
 Open-ILS/examples/fm_IDL.xml                       |   32 ++++++
 .../src/perlmods/lib/OpenILS/Application/Actor.pm  |  104 ++++++++++++++++++++
 .../lib/OpenILS/WWW/EGCatLoader/Account.pm         |   51 +++++++++-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |    2 +-
 Open-ILS/src/sql/Pg/005.schema.actors.sql          |   10 ++
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |   15 +++
 Open-ILS/src/sql/Pg/999.functions.global.sql       |    1 +
 .../upgrade/1144.schema.actor.privacy_waiver.sql   |   17 +++
 ...1145.function.privacy_waiver_in_purge_data.sql} |   12 ++-
 .../sql/Pg/upgrade/1146.data.privacy_waiver.sql    |   21 ++++
 .../src/templates/opac/myopac/prefs_settings.tt2   |   44 ++++++++-
 .../src/templates/staff/circ/patron/t_edit.tt2     |   49 +++++++++
 .../src/templates/staff/circ/patron/t_summary.tt2  |   14 +++
 .../web/js/ui/default/staff/circ/patron/regctl.js  |   43 ++++++++
 Open-ILS/web/js/ui/default/staff/services/user.js  |    1 +
 .../Circulation/privacy_waiver.adoc                |   15 +++
 16 files changed, 426 insertions(+), 5 deletions(-)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/1144.schema.actor.privacy_waiver.sql
 copy Open-ILS/src/sql/Pg/upgrade/{0901.schema.patron_purge_post_code.sql => 1145.function.privacy_waiver_in_purge_data.sql} (95%)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/1146.data.privacy_waiver.sql
 create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/privacy_waiver.adoc


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list