LP#1714070 Patron parent/guardian field
authorBill Erickson <berickxx@gmail.com>
Mon, 22 Oct 2018 00:10:19 +0000 (20:10 -0400)
committerJason Etheridge <jason@EquinoxInitiative.org>
Tue, 27 Nov 2018 05:07:23 +0000 (00:07 -0500)
Adds a new dedicated patron parent/guardian field.  This field is
editable in the patron edit interface, displays in the patron summary
side bar on the browser client, and is search-able from the patron
search interface in the browser client.

Adds patron editor "show" and "suggest" library settings.

Also adds a new library setting
'ui.patron.edit.guardian_required_for_juv' ("GUI: Juvenile account
requires parent/guardian").  When this setting is applied, a value
will be required in the patron editor when the juvenile flag is active.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Signed-off-by: Jason Etheridge <jason@EquinoxInitiative.org>
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/sql/Pg/005.schema.actors.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/999.functions.global.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.patron-guardian.sql [new file with mode: 0644]
Open-ILS/src/templates/staff/circ/patron/t_edit.tt2
Open-ILS/src/templates/staff/circ/patron/t_summary.tt2
Open-ILS/src/templates/staff/share/t_patron_search_form.tt2
Open-ILS/web/js/ui/default/staff/circ/patron/regctl.js

index c883f47..1be2c88 100644 (file)
@@ -3648,6 +3648,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <field reporter:label="Preferred Middle Name" name="pref_second_given_name" reporter:datatype="text"/>
                        <field reporter:label="Preferred Last Name" name="pref_family_name"  reporter:datatype="text"/>
                        <field reporter:label="Preferred Suffix" name="pref_suffix" reporter:datatype="text"/>
+                       <field reporter:label="Parent/Guardian" name="guardian" reporter:datatype="text"/>
                        <field reporter:label="Name Keywords" name="name_keywords" reporter:datatype="text"/>
                        <field reporter:label="Additional Permission Groups" name="groups" oils_persist:virtual="true" reporter:datatype="link"/>
                        <field reporter:label="Is Deleted" name="deleted" reporter:datatype="bool"/>
index 61d5bae..c387967 100644 (file)
@@ -42,6 +42,7 @@ CREATE TABLE actor.usr (
        second_given_name       TEXT,
        family_name             TEXT                            NOT NULL,
        suffix                  TEXT,
+    guardian        TEXT,
     pref_prefix TEXT,
     pref_first_given_name TEXT,
     pref_second_given_name TEXT,
@@ -93,6 +94,8 @@ CREATE INDEX actor_usr_first_given_name_unaccent_idx ON actor.usr (evergreen.una
 CREATE INDEX actor_usr_second_given_name_unaccent_idx ON actor.usr (evergreen.unaccent_and_squash(second_given_name));
 CREATE INDEX actor_usr_family_name_unaccent_idx ON actor.usr (evergreen.unaccent_and_squash(family_name));
 CREATE INDEX actor_usr_usrname_unaccent_idx ON actor.usr (evergreen.unaccent_and_squash(usrname));
+CREATE INDEX actor_usr_guardian_idx ON actor.usr (evergreen.lowercase(guardian));
+CREATE INDEX actor_usr_guardian_unaccent_idx ON actor.usr (evergreen.unaccent_and_squash(guardian));
 
 CREATE INDEX actor_usr_pref_first_given_name_idx ON actor.usr (evergreen.lowercase(pref_first_given_name));
 CREATE INDEX actor_usr_pref_second_given_name_idx ON actor.usr (evergreen.lowercase(pref_second_given_name));
index 949021b..e83dc04 100644 (file)
@@ -19414,4 +19414,46 @@ VALUES (
 );
 
 
+INSERT into config.org_unit_setting_type (name, label, description, datatype) 
+VALUES ( 
+    'ui.patron.edit.au.guardian.show',
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.show', 
+        'GUI: Show guardian field on patron registration', 
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.show', 
+        'The guardian field will be shown on the patron registration screen. Showing a field makes it appear with required fields even when not required. If the field is required this setting is ignored.', 
+        'coust', 'description'
+    ),
+    'bool'
+), (
+    'ui.patron.edit.au.guardian.suggest',
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.suggest', 
+        'GUI: Suggest guardian field on patron registration', 
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.suggest', 
+        'The guardian field will be suggested on the patron registration screen. Suggesting a field makes it appear when suggested fields are shown. If the field is shown or required this setting is ignored.', 
+        'coust', 'description'),
+    'bool'
+), (
+    'ui.patron.edit.guardian_required_for_juv',
+    oils_i18n_gettext(
+        'ui.patron.edit.guardian_required_for_juv',
+        'GUI: Juvenile account requires parent/guardian',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ui.patron.edit.guardian_required_for_juv',
+        'Require a value for the parent/guardian field in the patron editor for patrons marked as juvenile',
+        'coust', 'description'),
+    'bool'
+);
+
+
+
 
index 661ba4f..388d10b 100644 (file)
@@ -831,6 +831,7 @@ BEGIN
                        family_name = new_name,
                        suffix = NULL,
                        alias = NULL,
+            guardian = NULL,
                        day_phone = NULL,
                        evening_phone = NULL,
                        other_phone = NULL,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.patron-guardian.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.patron-guardian.sql
new file mode 100644 (file)
index 0000000..c63e1ce
--- /dev/null
@@ -0,0 +1,171 @@
+
+BEGIN;
+
+ALTER TABLE actor.usr ADD COLUMN guardian TEXT;
+
+CREATE INDEX actor_usr_guardian_idx 
+    ON actor.usr (evergreen.lowercase(guardian));
+CREATE INDEX actor_usr_guardian_unaccent_idx 
+    ON actor.usr (evergreen.unaccent_and_squash(guardian));
+
+-- Modify auditor tables accordingly.
+SELECT auditor.update_auditors();
+
+-- clear the guardian field on delete
+CREATE OR REPLACE FUNCTION actor.usr_delete(
+       src_usr  IN INTEGER,
+       dest_usr IN INTEGER
+) RETURNS VOID AS $$
+DECLARE
+       old_profile actor.usr.profile%type;
+       old_home_ou actor.usr.home_ou%type;
+       new_profile actor.usr.profile%type;
+       new_home_ou actor.usr.home_ou%type;
+       new_name    text;
+       new_dob     actor.usr.dob%type;
+BEGIN
+       SELECT
+               id || '-PURGED-' || now(),
+               profile,
+               home_ou,
+               dob
+       INTO
+               new_name,
+               old_profile,
+               old_home_ou,
+               new_dob
+       FROM
+               actor.usr
+       WHERE
+               id = src_usr;
+       --
+       -- Quit if no such user
+       --
+       IF old_profile IS NULL THEN
+               RETURN;
+       END IF;
+       --
+       perform actor.usr_purge_data( src_usr, dest_usr );
+       --
+       -- Find the root grp_tree and the root org_unit.  This would be simpler if we 
+       -- could assume that there is only one root.  Theoretically, someday, maybe,
+       -- there could be multiple roots, so we take extra trouble to get the right ones.
+       --
+       SELECT
+               id
+       INTO
+               new_profile
+       FROM
+               permission.grp_ancestors( old_profile )
+       WHERE
+               parent is null;
+       --
+       SELECT
+               id
+       INTO
+               new_home_ou
+       FROM
+               actor.org_unit_ancestors( old_home_ou )
+       WHERE
+               parent_ou is null;
+       --
+       -- Truncate date of birth
+       --
+       IF new_dob IS NOT NULL THEN
+               new_dob := date_trunc( 'year', new_dob );
+       END IF;
+       --
+       UPDATE
+               actor.usr
+               SET
+                       card = NULL,
+                       profile = new_profile,
+                       usrname = new_name,
+                       email = NULL,
+                       passwd = random()::text,
+                       standing = DEFAULT,
+                       ident_type = 
+                       (
+                               SELECT MIN( id )
+                               FROM config.identification_type
+                       ),
+                       ident_value = NULL,
+                       ident_type2 = NULL,
+                       ident_value2 = NULL,
+                       net_access_level = DEFAULT,
+                       photo_url = NULL,
+                       prefix = NULL,
+                       first_given_name = new_name,
+                       guardian = NULL,
+                       family_name = new_name,
+                       suffix = NULL,
+                       alias = NULL,
+            guardian = NULL,
+                       day_phone = NULL,
+                       evening_phone = NULL,
+                       other_phone = NULL,
+                       mailing_address = NULL,
+                       billing_address = NULL,
+                       home_ou = new_home_ou,
+                       dob = new_dob,
+                       active = FALSE,
+                       master_account = DEFAULT, 
+                       super_user = DEFAULT,
+                       barred = FALSE,
+                       deleted = TRUE,
+                       juvenile = DEFAULT,
+                       usrgroup = 0,
+                       claims_returned_count = DEFAULT,
+                       credit_forward_balance = DEFAULT,
+                       last_xact_id = DEFAULT,
+                       alert_message = NULL,
+                       create_date = now(),
+                       expire_date = now()
+       WHERE
+               id = src_usr;
+END;
+$$ LANGUAGE plpgsql;
+
+INSERT into config.org_unit_setting_type (name, label, description, datatype) 
+VALUES ( 
+    'ui.patron.edit.au.guardian.show',
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.show', 
+        'GUI: Show guardian field on patron registration', 
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.show', 
+        'The guardian field will be shown on the patron registration screen. Showing a field makes it appear with required fields even when not required. If the field is required this setting is ignored.', 
+        'coust', 'description'
+    ),
+    'bool'
+), (
+    'ui.patron.edit.au.guardian.suggest',
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.suggest', 
+        'GUI: Suggest guardian field on patron registration', 
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ui.patron.edit.au.guardian.suggest', 
+        'The guardian field will be suggested on the patron registration screen. Suggesting a field makes it appear when suggested fields are shown. If the field is shown or required this setting is ignored.', 
+        'coust', 'description'),
+    'bool'
+), (
+    'ui.patron.edit.guardian_required_for_juv',
+    oils_i18n_gettext(
+        'ui.patron.edit.guardian_required_for_juv',
+        'GUI: Juvenile account requires parent/guardian',
+        'coust', 'label'
+    ),
+    oils_i18n_gettext(
+        'ui.patron.edit.guardian_required_for_juv',
+        'Require a value for the parent/guardian field in the patron editor for patrons marked as juvenile',
+        'coust', 'description'),
+    'bool'
+);
+
+
+COMMIT;
+
index 3f95036..05e0d94 100644 (file)
@@ -393,6 +393,16 @@ within the "form" by name for validation.
   </div>
 </div>
 
+<!-- GUARDIAN -->
+
+<div class="row reg-field-row" ng-show="show_field('au.guardian')">
+  [% draw_field_label('au', 'guardian') %]
+  [% draw_form_input('au', 'guardian'); %]
+  <div class="col-md-6 patron-reg-example">
+    [% draw_example_text('au', 'guardian') %]
+  </div>
+</div>
+
 <!-- ident_type -->
 
 <div class="row reg-field-row" ng-show="show_field('au.ident_type')">
index 6b16b66..11cf06a 100644 (file)
       <div class="col-md-7" ng-show="now_show_dob()">{{patron().dob() | date:$root.egDateFormat}}</div>
     </div>
     <div class="row">
+      <div class="col-md-5">[% l('Parent/Guardian') %]</div>
+      <div class="col-md-7">{{patron().guardian()}}</div>
+    </div>
+    <div class="row">
       <div class="col-md-5">[% l('Last Activity') %]</div>
       <div class="col-md-7">{{patron().usr_activity()[0].event_time() | date:$root.egDateFormat}}</div>
     </div>
index e9de365..dd1a9dc 100644 (file)
         </div>
 
         <div class="col-md-2">
-          <div class="checkbox">
-            <label>
-              <input type="checkbox" ng-model="searchArgs.inactive" ng-change="onSearchInactiveChanged()"/>
-              [% l('Include Inactive?') %]
-            </label>
-          </div>
+          <input type="text" class="form-control" 
+            ng-model="searchArgs.guardian" placeholder="[% l('Parent/Guardian') %]"/>
         </div>
       </div>
       <div class="form-group" ng-show="showExtras">
           <input type="text" class="form-control" 
             ng-model="searchArgs.id" placeholder="[% l('Database ID') %]"/>
         </div>
+        <div class="col-md-2">
+          <div class="checkbox">
+            <label>
+              <input type="checkbox" ng-model="searchArgs.inactive" ng-change="onSearchInactiveChanged()"/>
+              [% l('Include Inactive?') %]
+            </label>
+          </div>
+        </div>
       </div>
     </form>
   </div>
index 7599020..cd8843a 100644 (file)
@@ -391,6 +391,9 @@ angular.module('egCoreMod')
             'ui.patron.edit.aua.post_code.regex',
             'ui.patron.edit.aua.post_code.example',
             'ui.patron.edit.aua.county.require',
+            'ui.patron.edit.au.guardian.show',
+            'ui.patron.edit.au.guardian.suggest',
+            'ui.patron.edit.guardian_required_for_juv',
             'format.date',
             'ui.patron.edit.default_suggested',
             'opac.barcode_regex',
@@ -1365,6 +1368,10 @@ function($scope , $routeParams , $q , $uibModal , $window , egCore ,
         apply_username_regex();
 
         add_date_watchers();
+
+        if ($scope.org_settings['ui.patron.edit.guardian_required_for_juv']) {
+            add_juv_watcher();
+        }
     });
 
     function add_date_watchers() {
@@ -1381,6 +1388,17 @@ function($scope , $routeParams , $q , $uibModal , $window , egCore ,
         // No need to watch expire_date
     }
 
+    function add_juv_watcher() {
+        $scope.$watch('patron.juvenile', function(newVal, oldVal) {
+            if (newVal === oldVal) return;
+            if (newVal) {
+                field_visibility['au.guardian'] = 3; // required
+            } else {
+                // Value will be reassessed by show_field()
+                delete field_visibility['au.guardian'];
+            }
+        });
+    }
 
     // update the currently displayed field documentation
     $scope.set_selected_field_doc = function(cls, field) {