From a6636a9807eb087bd55f4cea7db91d8bf6f5ebc2 Mon Sep 17 00:00:00 2001 From: Nick Clemens Date: Mon, 3 Jan 2022 15:24:01 +0000 Subject: [PATCH] Bug 28633: Add preferred name field to patrons This patch adds a new field 'preferred_name' to the patron record. Additionally it adds a method 'effective_name' to choose the preferred name if present and fall back to firstname The 'firstname' is displayed as 'First name' on the details page, with id/class patron_first_name to allow ajusting via JS/CSS if library wants to highlight/hide the non-preferred name PatronAutoComplete/ysearch is updated to use 'effective_name' method To test: 1 - Apply patches 2 - Update database and restart all, clear browser cache 3 - Load a patron in staff module 4 - Confirm you see and can add a preferred name 5 - Confirm the preferred name and first name now displays on patron details 6 - Remove first name from patron record and confirm it no longer shows 7 - Edit sysprefs BorrowerMandatoryFields and BorrowerUnwantedFields to confirm you can make new field required or hidden 8 - Sign in as patron to opac 9 - Confirm preferred name shows 10 - Edit account on opac and confirm field is present 11 - Verify DefaultPatronSearchFields contains 'preferredname' if your pref had firstname 12 - Perform checkout and patron search using preferred_name, confirm patron is found 13 - Enable PatronAutoComplete system preference 14 - Type patron's surname into Checkout or patron search but don't hit enter 15 - Confirm patron is displayed with 'preferred_name' in the preview Signed-off-by: Martin Renvoize https://bugs.koha-community.org/show_bug.cgi?id=24633 --- Koha/Patron.pm | 13 ++++ circ/ysearch.pl | 2 +- .../prog/en/includes/patron-title.inc | 13 +++- .../prog/en/includes/patronfields.inc | 1 + .../modules/admin/preferences/borrowers.json | 60 +++++++++++++++++++ .../en/modules/admin/preferences/patrons.pref | 2 +- .../prog/en/modules/members/memberentrygen.tt | 17 +++++- .../prog/en/modules/members/members-update.tt | 1 + .../prog/en/modules/members/moremember.tt | 8 ++- .../bootstrap/en/includes/patron-title.inc | 2 +- .../bootstrap/en/modules/opac-memberentry.tt | 15 ++++- t/db_dependent/Koha/Patron.t | 25 +++++++- 12 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/borrowers.json diff --git a/Koha/Patron.pm b/Koha/Patron.pm index e88e72551c..e7cba3a74b 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -107,6 +107,19 @@ sub new { return $class->SUPER::new($params); } +=head3 effective_name + +Return the preferred name for a patron, or their firstname if no +preferred name is set + +=cut + +sub effective_name { + my ( $self ) = @_; + + return $self->preferred_name || $self->firstname; +} + =head3 fixup_cardnumber Autogenerate next cardnumber from highest value found in database diff --git a/circ/ysearch.pl b/circ/ysearch.pl index 3f2650cbeb..c19031ad4f 100755 --- a/circ/ysearch.pl +++ b/circ/ysearch.pl @@ -84,7 +84,7 @@ while ( my $b = $borrowers_rs->next ) { push @borrowers, { borrowernumber => $b->borrowernumber, surname => $b->surname // '', - firstname => $b->firstname // '', + firstname => $b->effective_name // '', cardnumber => $b->cardnumber // '', dateofbirth => format_sqldatetime($b->dateofbirth, undef, undef, 1) // '', age => $b->get_age // '', diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc index 5a9b14d727..b8a05ee967 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc @@ -7,6 +7,8 @@ [%- SET data.surname = patron.surname -%] [%- SET data.othernames = patron.othernames -%] [%- SET data.firstname = patron.firstname -%] + [%- SET data.preferred_name = patron.preferred_name -%] + [%- SET data.effective_name = patron.effective_name -%] [%- SET data.cardnumber = patron.cardnumber -%] [%- SET data.borrowernumber = patron.borrowernumber -%] [%- SET data.title = patron.title -%] @@ -15,6 +17,8 @@ [%- SET data.surname = borrower.surname -%] [%- SET data.othernames = borrower.othernames -%] [%- SET data.firstname = borrower.firstname -%] + [%- SET data.preferred_name = borrower.preferred_name -%] + [%- SET data.effective_name = borrower.effective_name -%] [%- SET data.cardnumber = borrower.cardnumber -%] [%- SET data.borrowernumber = borrower.borrowernumber -%] [%- SET data.title = borrower.title -%] @@ -23,10 +27,15 @@ [%- SET data.surname = surname -%] [%- SET data.othernames = othernames -%] [%- SET data.firstname = firstname -%] + [%- SET data.preferred_name = preferred_name -%] + [%- SET data.effective_name = effective_name -%] [%- SET data.cardnumber = cardnumber -%] [%- SET data.borrowernumber = borrowernumber -%] [%- SET data.title = title -%] [%- END -%] +[%- UNLESS data.effective_name -%] + [%- SET data.effective_name = data.preferred_name || data.firstname -%] +[%- END -%] [%# Parameter no_html - if 1, the html tags are NOT generated %] [%- IF no_title %][% SET data.title = "" %][% END -%] [%- IF data.title %] @@ -61,9 +70,9 @@ [%- IF data.category_type == 'I' -%] [%- data.surname | html %] [% IF data.othernames %] ([% data.othernames | html %])[% END -%] [%- ELSIF invert_name -%] - [% data.title | $raw %][%- data.surname | html %][% IF ( data.firstname ) %], [% data.firstname | html %][% END %][% IF data.othernames %] ([% data.othernames | html %]) [% END -%] + [% data.title | $raw %][%- data.surname | html %][% IF ( data.effective_name ) %], [% data.effective_name | html %][% END %][% IF data.othernames %] ([% data.othernames | html %]) [% END -%] [%- ELSE -%] - [% data.title | $raw %][%- data.firstname | html %] [% IF data.othernames %] ([% data.othernames | html %]) [% END %] [% data.surname | html -%] + [% data.title | $raw %][%- data.effective_name | html %] [% IF data.othernames %] ([% data.othernames | html %]) [% END %] [% data.surname | html -%] [%- END -%] [%- IF display_cardnumber AND data.cardnumber %] ([% data.cardnumber | html %])[% END -%] [%- ELSIF display_cardnumber -%] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc index 5e1c58f38e..57321f92c5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patronfields.inc @@ -5,6 +5,7 @@ [%- CASE 'cardnumber' -%]Card number [%- CASE 'surname' -%]Surname [%- CASE 'firstname' -%]First name + [%- CASE 'preferred_name' -%]Preferred name [%- CASE 'title' -%]Salutation [%- CASE 'othernames' -%]Other name [%- CASE 'initials' -%]Initials diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/borrowers.json b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/borrowers.json new file mode 100644 index 0000000000..64336e1d6c --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/borrowers.json @@ -0,0 +1,60 @@ +{ + "cardnumber": "cardnumber", + "surname": "surname", + "firstname": "firstname", + "preferred_name": "preferred_name", + "title": "title", + "othernames": "othernames", + "initials": "initials", + "streetnumber": "streetnumber", + "streettype": "streettype", + "address": "address", + "address2": "address2", + "city": "city", + "state": "state", + "zipcode": "zipcode", + "country": "country", + "email": "email", + "phone": "phone", + "mobile": "mobile", + "fax": "fax", + "emailpro": "emailpro", + "phonepro": "phonepro", + "B_streetnumber": "B_streetnumber", + "B_streettype": "B_streettype", + "B_address": "B_address", + "B_address2": "B_address2", + "B_city": "B_city", + "B_state": "B_state", + "B_zipcode": "B_zipcode", + "B_country": "B_country", + "B_email": "B_email", + "B_phone": "B_phone", + "dateofbirth": "dateofbirth", + "dateenrolled": "dateenrolled", + "dateexpiry": "dateexpiry", + "branchcode": "branchcode", + "categorycode": "categorycode", + "contactname": "contactname", + "contactfirstname": "contactfirstname", + "borrowernotes": "borrowernotes", + "sex": "sex", + "password": "password", + "userid": "userid", + "opacnote": "opacnote", + "contactnote": "contactnote", + "altcontactfirstname": "altcontactfirstname", + "altcontactsurname": "altcontactsurname", + "altcontactaddress1": "altcontactaddress1", + "altcontactaddress2": "altcontactaddress2", + "altcontactaddress3": "altcontactaddress3", + "altcontactstate": "altcontactstate", + "altcontactzipcode": "altcontactzipcode", + "altcontactcountry": "altcontactcountry", + "altcontactphone": "altcontactphone", + "smsalertnumber": "smsalertnumber", + "autorenew_checkouts": "autorenew_checkouts", + "primary_contact_method": "primary_contact_method", + "sort1": "sort1", + "sort2": "sort2" +} diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref index 256962915b..c332432996 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref @@ -48,7 +48,7 @@ Patrons: - "Comma separated list defining the default fields to be used during a patron search using the \"standard\" option:" - pref: DefaultPatronSearchFields class: multi - - "If empty Koha will default to \"firstname,surname,othernames,cardnumber,userid\". Additional fields added to this preference will be added as search options in the dropdown menu on the patron search page." + - "If empty Koha will default to \"firstname,surname,preferred_name,othernames,cardnumber,userid\". Additional fields added to this preference will be added as search options in the dropdown menu on the patron search page." - - "Show the following fields from the items database table as columns on the statistics tab on the patron record: " - pref: StatisticsFields diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt index 9f64400a89..bfb4415f38 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt @@ -264,7 +264,7 @@ legend:hover { [% END %] [% IF ( step_1 ) %] - [% UNLESS notitle && nosurname && nofirstname && nodateofbirth && noinitials && noothernames &&nosex %] + [% UNLESS notitle && nosurname && nofirstname && nopreferred_name && nodateofbirth && noinitials && noothernames &&nosex %]
[% IF ( I ) %]Organization [% ELSE %]Patron [% END %]identity
    @@ -338,6 +338,21 @@ legend:hover { [% END %] [% END #/UNLESS nofirstname %] + [% UNLESS nopreferred_name %] +
  1. + [% IF ( mandatorypreferred_name ) %] +
  2. + [% END #/UNLESS nopreferred_name %] [% UNLESS nodateofbirth %]
  3. [% IF ( mandatorydateofbirth ) %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/members-update.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/members-update.tt index 93bb308d9d..1e13f4b5de 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/members-update.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/members-update.tt @@ -19,6 +19,7 @@ [% CASE 'branchcode' %]Home library (branchcode) [% CASE 'surname' %]Surname [% CASE 'firstname' %]First name +[% CASE 'preferred_name' %]Preferred name [% CASE 'title' %]Title [% CASE 'othernames' %]Other names [% CASE 'initials' %]Initials diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt index f62109cb17..e1948ecd9b 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt @@ -87,7 +87,7 @@

    [% UNLESS ( I ) %] - [% patron.title | html %] [% patron.firstname | html %] + [% patron.title | html %] [% patron.effective_name | html %] [% END %] [% patron.surname | html %] ([% patron.cardnumber | html %])

    @@ -125,6 +125,12 @@
      + [% IF ( patron.preferred_name && patron.firstname ) %] +
    1. + First name: + [% patron.firstname | html %] +
    2. + [% END %] [% IF ( patron.phone ) %]
    3. Primary phone: diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/patron-title.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/patron-title.inc index d77961d713..4b87c83aaa 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/patron-title.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/patron-title.inc @@ -4,5 +4,5 @@ [%- IF patron.title -%] [% patron.title | html %] [%- END -%] - [% patron.firstname | html %] [% patron.surname | html %] + [% patron.effective_name | html %] [% patron.surname | html %] [%- END -%] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt index 4e1a4fd692..eb4e44da06 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt @@ -176,7 +176,7 @@ Guaranteed by [% FOREACH gr IN patron.guarantor_relationships %] [% SET g = gr.guarantor %] - [% g.firstname | html %] [% g.surname | html %] + [% g.effective_name | html %] [% g.surname | html %] [%- IF ! loop.last %], [% END %] [% END %] @@ -193,7 +193,7 @@
      - [% FOREACH field = ['streetnumber' 'streettype' 'cardnumber' 'branchcode' 'categorycode' 'title' 'surname' 'firstname' 'dateofbirth' 'initials' 'othernames' 'address' 'address2' 'city' 'state' 'zipcode' 'country' 'phone' 'phonepro' 'mobile' 'email' 'emailpro' 'fax' 'B_streettype' 'B_address' 'B_address2' 'B_city' 'B_state' 'B_zipcode' 'B_country' 'B_phone' 'B_email' 'contactnote' 'altcontactsurname' 'altcontactfirstname' 'altcontactaddress1' 'altcontactaddress2' 'altcontactaddress3' 'altcontactstate' 'altcontactzipcode' 'altcontactcountry' 'altcontactphone' 'password' ] %] + [% FOREACH field = ['streetnumber' 'streettype' 'cardnumber' 'branchcode' 'categorycode' 'title' 'surname' 'firstname' 'preferred_name' 'dateofbirth' 'initials' 'othernames' 'address' 'address2' 'city' 'state' 'zipcode' 'country' 'phone' 'phonepro' 'mobile' 'email' 'emailpro' 'fax' 'B_streettype' 'B_address' 'B_address2' 'B_city' 'B_state' 'B_zipcode' 'B_country' 'B_phone' 'B_email' 'contactnote' 'altcontactsurname' 'altcontactfirstname' 'altcontactaddress1' 'altcontactaddress2' 'altcontactaddress3' 'altcontactstate' 'altcontactzipcode' 'altcontactcountry' 'altcontactphone' 'password' ] %] [% IF mandatory.defined( field ) %] [% SET required.$field = 'required' %] [% END %] @@ -300,7 +300,7 @@ [% END # / defined 'branchcode' %] [%# Following on one line for translatability %] - [% UNLESS hidden.defined('title') && hidden.defined('surname') && hidden.defined('firstname') && hidden.defined('dateofbirth') && hidden.defined('initials') && hidden.defined('othernames') && hidden.defined('sex') %] + [% UNLESS hidden.defined('title') && hidden.defined('surname') && hidden.defined('firstname') && hidden.defined('preferred_name') && hidden.defined('dateofbirth') && hidden.defined('initials') && hidden.defined('othernames') && hidden.defined('sex') %]
      @@ -343,6 +343,15 @@
    4. [% END %] + [% UNLESS hidden.defined('preferred_name') %] +
    5. + + + +
      Required
      +
    6. + [% END %] + [% UNLESS hidden.defined('dateofbirth') %]
    7. diff --git a/t/db_dependent/Koha/Patron.t b/t/db_dependent/Koha/Patron.t index 6418d6066f..5aaedd2de8 100755 --- a/t/db_dependent/Koha/Patron.t +++ b/t/db_dependent/Koha/Patron.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 16; +use Test::More tests => 17; use Test::Exception; use Test::Warn; @@ -1137,3 +1137,26 @@ subtest 'recalls() tests' => sub { $schema->storage->txn_rollback; }; + +subtest 'effective_name() tests' => sub { + + plan tests => 2; + + $schema->storage->txn_begin; + + my $patron_1 = $builder->build_object({ class => 'Koha::Patrons', value => { + firstname => 'John', + preferred_name => 'Jacob', + } + }); + my $patron_2 = $builder->build_object({ class => 'Koha::Patrons', value=> { + firstname => "Bob", + preferred_name => undef, + } + }); + + is( $patron_1->effective_name, "Jacob", 'Preferred name correctly chosen' ); + is( $patron_2->effective_name, "Bob", 'First name correctly chosen if no preferred name' ); + + $schema->storage->txn_rollback; +}; -- 2.20.1