Bug 21978: Add support for middle name

This patch adds the new 'Middle name' field to the patron record.

To test:
1) Apply patches
2) Update database, restart all and clear the browser cache
3) Load a patron in the staff module
4) Confirm you can see and edit the new 'Middle name' field
5) Confirm the new middle name data displays on patron details
6) Confirm the new middle name data displays on patron search results
7) Confirm the new middle name data displays everywhere patron names are
   displayed.
8) Confirm the new middle name data displays on the OPAC
9) Confirm the 'Middle name' field appears in the OPAC borrower
   modification screens
10) Edit sysprefs `BorrowerMandatoryFields`, `BorrowerUnwantedFields`,
    `SelfModificationBorrowerUnwantedField`, `PatronSelfModificationMandatoryField`,
    `PatronSelfRegistrationBorrowerMandatoryField` and
    `PatronSelfRegistrationBorrowerUnwantedField` to confirm you can make
    the new field required or hidden.
11) Verify that DefaultPatronSearchFields contains the new field if you
    already had 'firstname' in the field list
12) Enable PatronAutoComplete system preference
13) Type patrons surname into checkout or patron search but don't hit
    return
14) Confirm the patrons middle name is displayed in the preview
15) Go to tools > patron lists and attempt to add a patron to a list
16) Patrons middle name should appear in the autocomplete here too

Signed-off-by: Sally <sally.healey@cheshiresharedservices.gov.uk>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
Martin Renvoize 2022-04-19 16:20:51 +01:00 committed by Tomas Cohen Arazi
parent 8993c39b7a
commit d5608b8ff0
Signed by: tomascohen
GPG key ID: 0A272EA1B2F3C15F
15 changed files with 77 additions and 40 deletions

View file

@ -63,6 +63,7 @@ sub columns {
"title" => __("Salutation"),
"surname" => __("Surname"),
"firstname" => __("First name"),
"middle_name" => __("Middle name"),
"dateofbirth" => __("Date of birth"),
"initials" => __("Initials"),
"othernames" => __("Other name"),

View file

@ -59,9 +59,10 @@ foreach my $p (@parts) {
push(
@params,
-or => [
surname => { -like => "%$p%" },
firstname => { -like => "%$p%" },
cardnumber => { -like => "$p%" },
surname => { -like => "%$p%" },
firstname => { -like => "%$p%" },
middle_name => { -like => "%$p%" },
cardnumber => { -like => "$p%" },
]
);
}
@ -74,7 +75,7 @@ my $borrowers_rs = Koha::Patrons->search_limited(
# Get the first 10 results
page => 1,
rows => 10,
order_by => [ 'surname', 'firstname' ],
order_by => [ 'surname', 'firstname', 'middle_name' ],
prefetch => 'branchcode',
},
);
@ -82,18 +83,20 @@ my $borrowers_rs = Koha::Patrons->search_limited(
my @borrowers;
while ( my $b = $borrowers_rs->next ) {
push @borrowers,
{ borrowernumber => $b->borrowernumber,
surname => $b->surname // '',
firstname => $b->firstname // '',
cardnumber => $b->cardnumber // '',
dateofbirth => format_sqldatetime($b->dateofbirth, undef, undef, 1) // '',
age => $b->get_age // '',
address => $b->address // '',
city => $b->city // '',
zipcode => $b->zipcode // '',
country => $b->country // '',
branchcode => $b->branchcode // '',
branchname => $b->library->branchname // '',
{
borrowernumber => $b->borrowernumber,
surname => $b->surname // '',
firstname => $b->firstname // '',
middle_name => $b->middle_name // '',
cardnumber => $b->cardnumber // '',
dateofbirth => format_sqldatetime( $b->dateofbirth, undef, undef, 1 ) // '',
age => $b->get_age // '',
address => $b->address // '',
city => $b->city // '',
zipcode => $b->zipcode // '',
country => $b->country // '',
branchcode => $b->branchcode // '',
branchname => $b->library->branchname // '',
};
}

View file

@ -12,7 +12,7 @@ function patron_autocomplete(params) {
if ( field_to_retrieve == 'borrowernumber' ) {
field = ui.item.borrowernumber;
}
AddPatron( ui.item.firstname + " " + ui.item.surname, field, patron_container, patron_input_name );
AddPatron( ui.item.firstname + " " + ui.item.middle_name + " " + ui.item.surname, field, patron_container, patron_input_name );
input_autocomplete.val('').focus();
return false;
}
@ -20,7 +20,7 @@ function patron_autocomplete(params) {
.data( "ui-autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "ui-autocomplete-item", item )
.append( "<a>" + item.surname + ", " + item.firstname + " (" + item.cardnumber + ") <small>" + item.address + " " + item.city + " " + item.zipcode + " " + item.country + "</small></a>" )
.append( "<a>" + item.surname + ", " + item.firstname + " " + item.middle_name + " (" + item.cardnumber + ") <small>" + item.address + " " + item.city + " " + item.zipcode + " " + item.country + "</small></a>" )
.appendTo( ul );
};

View file

@ -19,8 +19,12 @@
}
var name;
var firstname = escape_str(patron.firstname);
var surname = escape_str(patron.surname);
var firstname = escape_str(patron.firstname);
var surname = escape_str(patron.surname);
if ( patron.middle_name != null && patron.middle_name != '' ) {
firstname += ' ' + escape_str(patron.middle_name);
}
if ( patron.other_name != null && patron.other_name != '' ) {
firstname += ' (' + escape_str(patron.other_name) + ')';

View file

@ -87,7 +87,11 @@
// Display card number in parentheses if it exists
cardnumber = " (" + item.cardnumber + ") ";
}
var itemString = "<a href=\"" + item.link + "\">" + ( item.surname ? item.surname.escapeHtml() : "" ) + ", " + ( item.firstname ? item.firstname.escapeHtml() : "" ) + cardnumber.escapeHtml() + " <small>";
var itemString = "<a href=\"" + item.link + "\">" + ( item.surname ? item.surname.escapeHtml() : "" ) + ", "
+ ( item.firstname ? item.firstname.escapeHtml() : "" )
+ ( item.middle_name ? " " + item.middle_name.escapeHtml() : "" )
+ cardnumber.escapeHtml()
+ " <small>";
if( item.branchcode == loggedInLibrary ){
loggedInClass = "ac-currentlibrary";
@ -150,6 +154,7 @@
.append(
"<a href=\"" + item.link + "\">" + ( item.surname ? item.surname.escapeHtml() : "" ) + ", "
+ ( item.firstname ? item.firstname.escapeHtml() : "" )
+ ( item.middle_name ? " " + item.middle_name.escapeHtml() : "" )
+ cardnumber.escapeHtml()
+ " <small>"
+ ( item.dateofbirth ? item.dateofbirth.escapeHtml() : "" ) + " "

View file

@ -23,7 +23,7 @@
<div id="filters">
<p><label for="searchfieldstype">Search fields:</label>
<select name="searchfieldstype" id="searchfieldstype">
[% SET standard = Koha.Preference('DefaultPatronSearchFields') || 'firstname,surname,othernames,cardnumber,userid' %]
[% SET standard = Koha.Preference('DefaultPatronSearchFields') || 'firstname,middle_name,surname,othernames,cardnumber,userid' %]
[% default_fields = [ standard, 'surname', 'cardnumber', 'email', 'borrowernumber', 'userid', 'phone', 'address', 'dateofbirth', 'sort1', 'sort2' ] %]
[% search_options = default_fields.merge(standard.split(',')).unique %]
[% FOREACH s_o IN search_options %]

View file

@ -60,7 +60,7 @@
<li>
<label for="searchfieldstype_filter">Search field:</label>
<select name="searchfieldstype" id="searchfieldstype_filter">
[% SET standard = Koha.Preference('DefaultPatronSearchFields') || 'firstname,surname,othernames,cardnumber,userid' %]
[% SET standard = Koha.Preference('DefaultPatronSearchFields') || 'firstname,middle_name,surname,othernames,cardnumber,userid' %]
[% default_fields = [ standard, 'surname', 'cardnumber', 'email', 'borrowernumber', 'userid', 'phone', 'address', 'dateofbirth', 'sort1', 'sort2' ] %]
[% search_options = default_fields.merge(standard.split(',')).unique %]
[% FOREACH s_o IN search_options %]
@ -317,7 +317,7 @@
let search_type = $("#searchtype_filter").val() || "contain";
let search_fields = $("#searchfieldstype_filter").val();
if ( !search_fields ) {
search_fields = "[% Koha.Preference('DefaultPatronSearchFields') || 'firstname,surname,othernames,cardnumber,userid' | html %]";
search_fields = "[% Koha.Preference('DefaultPatronSearchFields') || 'firstname,middle_name,surname,othernames,cardnumber,userid' | html %]";
}
let subquery_and = [];
@ -458,7 +458,7 @@
}
[% CASE 'name-address' %]
{
"data": "me.surname:me.firstname:me.othernames:me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
"data": "me.surname:me.firstname:me.middle_name:me.othernames:me.street_number:me.address:me.address2:me.city:me.state:me.postal_code:me.country",
"searchable": true,
"orderable": true,
"render": function( data, type, row, meta ) {
@ -508,7 +508,7 @@
}
[% CASE 'name' %]
{
"data": "me.surname:me.firstname:me.othernames",
"data": "me.surname:me.firstname:me.middle_name:me.othernames",
"searchable": true,
"orderable": true,
"render": function( data, type, row, meta ) {

View file

@ -7,6 +7,7 @@
[%- SET data.surname = patron.surname -%]
[%- SET data.othernames = patron.othernames -%]
[%- SET data.firstname = patron.firstname -%]
[%- SET data.middle_name = patron.middle_name -%]
[%- SET data.cardnumber = patron.cardnumber -%]
[%- SET data.borrowernumber = patron.borrowernumber -%]
[%- SET data.title = patron.title -%]
@ -15,6 +16,7 @@
[%- SET data.surname = borrower.surname -%]
[%- SET data.othernames = borrower.othernames -%]
[%- SET data.firstname = borrower.firstname -%]
[%- SET data.middle_name = borrower.middle_name -%]
[%- SET data.cardnumber = borrower.cardnumber -%]
[%- SET data.borrowernumber = borrower.borrowernumber -%]
[%- SET data.title = borrower.title -%]
@ -23,6 +25,7 @@
[%- SET data.surname = surname -%]
[%- SET data.othernames = othernames -%]
[%- SET data.firstname = firstname -%]
[%- SET data.middle_name = middle_name -%]
[%- SET data.cardnumber = cardnumber -%]
[%- SET data.borrowernumber = borrowernumber -%]
[%- SET data.title = title -%]
@ -61,9 +64,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.firstname ) %], [% data.firstname | html %][% END %][% IF data.middle_name %] [% data.middle_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.firstname | html %][% IF data.middle_name %] [% data.middle_name | html %][% END %][% IF data.othernames %] ([% data.othernames | html %]) [% END %] [% data.surname | html -%]
[%- END -%]
[%- IF display_cardnumber AND data.cardnumber %] ([% data.cardnumber | html %])[% END -%]
[%- ELSIF display_cardnumber -%]

View file

@ -5,6 +5,7 @@
[%- CASE 'cardnumber' -%]<span>Card number</span>
[%- CASE 'surname' -%]<span>Surname</span>
[%- CASE 'firstname' -%]<span>First name</span>
[%- CASE 'middle_name' -%]<span>Middle name</span>
[%- CASE 'title' -%]<span>Salutation</span>
[%- CASE 'othernames' -%]<span>Other name</span>
[%- CASE 'initials' -%]<span>Initials</span>

View file

@ -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,middle_name,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."
-
- "Show the following fields from the items database table as columns on the statistics tab on the patron record: "
- pref: StatisticsFields

View file

@ -267,7 +267,7 @@ legend:hover {
[% END %]
[% IF ( step_1 ) %]
[% UNLESS notitle && nosurname && nofirstname && nodateofbirth && noinitials && noothernames &&nosex %]
[% UNLESS notitle && nosurname && nofirstname && nomiddle_name && nodateofbirth && noinitials && noothernames &&nosex %]
<fieldset class="rows" id="memberentry_identity">
<legend id="identity_lgd">[% IF ( I ) %]<span>Organization</span> [% ELSE %]<span>Patron</span> [% END %]<span>identity</span></legend>
<ol>
@ -341,6 +341,21 @@ legend:hover {
[% END %]
</li>
[% END #/UNLESS nofirstname %]
[% UNLESS nomiddle_name %]
<li>
[% IF ( mandatorymiddle_name ) %]
<label for="middle_name" class="required">
[% ELSE %]
<label for="middle_name">
[% END %]
Middle name:
</label>
<input type="text" id="middle_name" name="middle_name" size="20" value="[% borrower_data.middle_name | html UNLESS opduplicate %]" />
[% IF ( mandatorymiddle_name ) %]
<span class="required">Required</span>
[% END %]
</li>
[% END #/UNLESS nomiddle_name %]
[% UNLESS nodateofbirth %]
<li>
[% IF ( mandatorydateofbirth ) %]

View file

@ -19,6 +19,7 @@
[% CASE 'branchcode' %]<span>Home library (branchcode)</span>
[% CASE 'surname' %]<span>Surname</span>
[% CASE 'firstname' %]<span>First name</span>
[% CASE 'middle_name' %]<span>Middle name</span>
[% CASE 'title' %]<span>Title</span>
[% CASE 'othernames' %]<span>Other names</span>
[% CASE 'initials' %]<span>Initials</span>

View file

@ -95,12 +95,7 @@
[% INCLUDE 'patron_messages.inc' %]
</div>
<h1>
[% UNLESS ( I ) %]
[% patron.title | html %] [% patron.firstname | html %]
[% END %]
[% patron.surname | html %] ([% patron.cardnumber | html %])
</h1>
<h1>[% INCLUDE 'patron-title.inc' no_html = 1 %]</h1>
<div class="col-sm-6">
<div id="patron-information" class="patroninfo-section">

View file

@ -4,5 +4,5 @@
[%- IF patron.title -%]
<span class="patron-title">[% patron.title | html %]</span>
[%- END -%]
[% patron.firstname | html %] [% patron.surname | html %]
[% patron.firstname | html %] [% patron.middle_name | html %] [% patron.surname | html %]
[%- END -%]

View file

@ -176,7 +176,7 @@
Guaranteed by
[% FOREACH gr IN patron.guarantor_relationships %]
[% SET g = gr.guarantor %]
[% g.firstname | html %] [% g.surname | html %]
[% g.firstname | html %] [% g.middle_name | html %] [% g.surname | html %]
[%- IF ! loop.last %], [% END %]
[% END %]
</span>
@ -193,7 +193,7 @@
<form method="post" action="/cgi-bin/koha/opac-memberentry.pl" id="memberentry-form" autocomplete="off">
[% 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' 'middle_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('middle_name') && hidden.defined('dateofbirth') && hidden.defined('initials') && hidden.defined('othernames') && hidden.defined('sex') %]
<div class="row">
<div class="col">
<fieldset class="rows" id="memberentry_identity">
@ -343,6 +343,15 @@
</li>
[% END %]
[% UNLESS hidden.defined('middle_name') %]
<li>
<label for="borrower_middle_name" class="[% required.middle_name | html %]">Middle name:</label>
<input type="text" id="borrower_middle_name" name="borrower_middle_name" value="[% borrower.middle_name | html %]" class="[% required.middle_name | html %]" />
<div class="required_label [% required.middle_name | html %]">Required</div>
</li>
[% END %]
[% UNLESS hidden.defined('dateofbirth') %]
<li>
<label for="borrower_dateofbirth" class="[% required.dateofbirth | html %]">Date of birth:</label>