From 963e616bb32660c57bbbb4d705e0465007c7ce95 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Wed, 28 Mar 2012 17:43:13 +0200 Subject: [PATCH 1/1] But 5742: Batch edit patrons new permission : edit_patrons Plan test: - Go on the page: tools > Patrons modification (modborrowers.pl) - Enter a list of cardnumbers (or use a file) - Modify one or more patron's fields (you can modify surname, firstname, branchname, category, sort1, sort2, date of enrollment, date of expiry, debarred date, debarred comment and borrower note) - Save - Check on the result page (or in database for non-displayed fields) if modifications have been correctly made. - re test with different attributes. For each attributes filled with an authorized value category, you can select a value in a drop-down list. Else it's a free input text. If your attribute is filled with a patron category, the modification performs only on patrons belonging to this category - Save - Verify on the result page --- C4/Members.pm | 151 +++++---- C4/Members/Attributes.pm | 56 +++- .../data/mysql/de-DE/mandatory/userpermissions.sql | 1 + .../data/mysql/en/mandatory/userpermissions.sql | 1 + .../data/mysql/es-ES/mandatory/userpermissions.sql | 1 + .../mysql/fr-FR/1-Obligatoire/userpermissions.sql | 1 + .../data/mysql/it-IT/necessari/userpermissions.sql | 1 + .../mysql/nb-NO/1-Obligatorisk/userpermissions.sql | 1 + .../data/mysql/pl-PL/mandatory/userpermissions.sql | 1 + installer/data/mysql/updatedatabase.pl | 10 + .../prog/en/modules/tools/modborrowers.tt | 310 +++++++++++++++++++ .../prog/en/modules/tools/tools-home.tt | 5 + tools/modborrowers.pl | 322 ++++++++++++++++++++ 13 files changed, 789 insertions(+), 72 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt create mode 100755 tools/modborrowers.pl diff --git a/C4/Members.pm b/C4/Members.pm index 6161ac9..5290b0e 100644 --- a/C4/Members.pm +++ b/C4/Members.pm @@ -42,86 +42,87 @@ use Koha::DateUtils; our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,$debug); BEGIN { - $VERSION = 3.02; - $debug = $ENV{DEBUG} || 0; - require Exporter; - @ISA = qw(Exporter); - #Get data - push @EXPORT, qw( - &Search - &GetMemberDetails + $VERSION = 3.02; + $debug = $ENV{DEBUG} || 0; + require Exporter; + @ISA = qw(Exporter); + #Get data + push @EXPORT, qw( + &Search + &GetMemberDetails &GetMemberRelatives - &GetMember + &GetMember - &GetGuarantees + &GetGuarantees - &GetMemberIssuesAndFines - &GetPendingIssues - &GetAllIssues + &GetMemberIssuesAndFines + &GetPendingIssues + &GetAllIssues - &get_institutions - &getzipnamecity - &getidcity + &get_institutions + &getzipnamecity + &getidcity - &GetFirstValidEmailAddress + &GetFirstValidEmailAddress - &GetAge - &GetCities - &GetRoadTypes - &GetRoadTypeDetails - &GetSortDetails - &GetTitles + &GetAge + &GetCities + &GetRoadTypes + &GetRoadTypeDetails + &GetSortDetails + &GetTitles - &GetPatronImage - &PutPatronImage - &RmPatronImage + &GetPatronImage + &PutPatronImage + &RmPatronImage - &GetHideLostItemsPreference + &GetHideLostItemsPreference - &IsMemberBlocked - &GetMemberAccountRecords - &GetBorNotifyAcctRecord + &IsMemberBlocked + &GetMemberAccountRecords + &GetBorNotifyAcctRecord - &GetborCatFromCatType - &GetBorrowercategory - &GetBorrowercategoryList + &GetborCatFromCatType + &GetBorrowercategory + GetBorrowerCategorycode + &GetBorrowercategoryList - &GetBorrowersWhoHaveNotBorrowedSince - &GetBorrowersWhoHaveNeverBorrowed - &GetBorrowersWithIssuesHistoryOlderThan + &GetBorrowersWhoHaveNotBorrowedSince + &GetBorrowersWhoHaveNeverBorrowed + &GetBorrowersWithIssuesHistoryOlderThan - &GetExpiryDate + &GetExpiryDate - &AddMessage - &DeleteMessage - &GetMessages - &GetMessagesCount + &AddMessage + &DeleteMessage + &GetMessages + &GetMessagesCount &IssueSlip - GetBorrowersWithEmail - ); + GetBorrowersWithEmail + ); - #Modify data - push @EXPORT, qw( - &ModMember - &changepassword + #Modify data + push @EXPORT, qw( + &ModMember + &changepassword &ModPrivacy - ); - - #Delete data - push @EXPORT, qw( - &DelMember - ); - - #Insert data - push @EXPORT, qw( - &AddMember - &add_member_orgs - &MoveMemberToDeleted - &ExtendMemberSubscriptionTo - ); - - #Check data + ); + + #Delete data + push @EXPORT, qw( + &DelMember + ); + + #Insert data + push @EXPORT, qw( + &AddMember + &add_member_orgs + &MoveMemberToDeleted + &ExtendMemberSubscriptionTo + ); + + #Check data push @EXPORT, qw( &checkuniquemember &checkuserpassword @@ -1409,10 +1410,6 @@ sub GetborCatFromCatType { Given the borrower's category code, the function returns the corresponding data hashref for a comprehensive information display. - $arrayref_hashref = &GetBorrowercategory; - -If no category code provided, the function returns all the categories. - =cut sub GetBorrowercategory { @@ -1433,6 +1430,26 @@ sub GetBorrowercategory { return; } # sub getborrowercategory + +=head2 GetBorrowerCategorycode + + $categorycode = &GetBorrowerCategoryCode( $borrowernumber ); + +Given the borrowernumber, the function returns the corresponding categorycode +=cut + +sub GetBorrowerCategorycode { + my ( $borrowernumber ) = @_; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( qq{ + SELECT categorycode + FROM borrowers + WHERE borrowernumber = ? + } ); + $sth->execute( $borrowernumber ); + return $sth->fetchrow; +} + =head2 GetBorrowercategoryList $arrayref_hashref = &GetBorrowercategoryList; diff --git a/C4/Members/Attributes.pm b/C4/Members/Attributes.pm index 33d2407..b373c94 100644 --- a/C4/Members/Attributes.pm +++ b/C4/Members/Attributes.pm @@ -32,8 +32,9 @@ BEGIN { $VERSION = 3.01; @ISA = qw(Exporter); @EXPORT_OK = qw(GetBorrowerAttributes GetBorrowerAttributeValue CheckUniqueness SetBorrowerAttributes + DeleteBorrowerAttribute UpdateBorrowerAttribute extended_attributes_code_value_arrayref extended_attributes_merge - SearchIdMatchingAttribute); + SearchIdMatchingAttribute); %EXPORT_TAGS = ( all => \@EXPORT_OK ); } @@ -76,18 +77,19 @@ sub GetBorrowerAttributes { FROM borrower_attributes JOIN borrower_attribute_types USING (code) LEFT JOIN authorised_values ON (category = authorised_value_category AND attribute = authorised_value) - WHERE borrowernumber = ?"; + WHERE 1"; + $query .= "\nAND borrowernumber = ?" if $borrowernumber; $query .= "\nAND opac_display = 1" if $opac_only; $query .= "\nORDER BY code, attribute"; my $sth = $dbh->prepare_cached($query); - $sth->execute($borrowernumber); + $sth->execute($borrowernumber ? $borrowernumber : ()); my @results = (); while (my $row = $sth->fetchrow_hashref()) { push @results, { code => $row->{'code'}, description => $row->{'description'}, - value => $row->{'attribute'}, - value_description => $row->{'lib'}, + value => $row->{'attribute'}, + value_description => $row->{'lib'}, password => $row->{'password'}, display_checkout => $row->{'display_checkout'}, category_code => $row->{'category_code'}, @@ -233,6 +235,50 @@ sub SetBorrowerAttributes { return 1; # borower attributes successfully set } +=head2 DeleteBorrowerAttribute + + DeleteBorrowerAttribute($borrowernumber, $attribute); + +Delete a borrower attribute for the patron identified by C<$borrowernumber> and the attribute code of C<$attribute> + +=cut +sub DeleteBorrowerAttribute { + my ( $borrowernumber, $attribute ) = @_; + + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(qq{ + DELETE FROM borrower_attributes + WHERE borrowernumber = ? + AND code = ? + } ); + $sth->execute( $borrowernumber, $attribute->{code} ); +} + +=head2 UpdateBorrowerAttribute + + UpdateBorrowerAttribute($borrowernumber, $attribute ); + +Update a borrower attribute C<$attribute> for the patron identified by C<$borrowernumber>, + +=cut +sub UpdateBorrowerAttribute { + my ( $borrowernumber, $attribute ) = @_; + + DeleteBorrowerAttribute $borrowernumber, $attribute; + + my $dbh = C4::Context->dbh; + my $query = "INSERT INTO borrower_attributes SET attribute = ?, code = ?, borrowernumber = ?"; + my @params = ( $attribute->{attribute}, $attribute->{code}, $borrowernumber ); + if ( defined $attribute->{password} ) { + $query .= ", password = ?"; + push @params, $attribute->{password}; + } + my $sth = $dbh->prepare( $query ); + + $sth->execute( @params ); +} + + =head2 extended_attributes_code_value_arrayref my $patron_attributes = "homeroom:1150605,grade:01,extradata:foobar"; diff --git a/installer/data/mysql/de-DE/mandatory/userpermissions.sql b/installer/data/mysql/de-DE/mandatory/userpermissions.sql index 2302273..28326bd 100644 --- a/installer/data/mysql/de-DE/mandatory/userpermissions.sql +++ b/installer/data/mysql/de-DE/mandatory/userpermissions.sql @@ -28,6 +28,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES (13, 'manage_staged_marc', 'MARC-Importe verwalten, auch Übernahme in Katalog und Import rückgängig machen'), (13, 'export_catalog', 'Titel- und Exemplardaten exportieren'), (13, 'import_patrons', 'Benutzerdaten importieren'), + (13, 'edit_patrons', 'Perform batch modification of patrons'), (13, 'delete_anonymize_patrons', 'Inaktive Benutzer löschen und Ausleihhistorie anonymisieren (Benutzerausleihhistorie löschen)'), (13, 'batch_upload_patron_images', 'Benutzerfotos einzeln oder im Stapel hochladen'), (13, 'schedule_tasks', 'Aufgabenplaner verwenden'), diff --git a/installer/data/mysql/en/mandatory/userpermissions.sql b/installer/data/mysql/en/mandatory/userpermissions.sql index 873089a..da61f69 100644 --- a/installer/data/mysql/en/mandatory/userpermissions.sql +++ b/installer/data/mysql/en/mandatory/userpermissions.sql @@ -28,6 +28,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'), (13, 'export_catalog', 'Export bibliographic and holdings data'), (13, 'import_patrons', 'Import patron data'), + (13, 'edit_patrons', 'Perform batch modification of patrons'), (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'), (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'), (13, 'schedule_tasks', 'Schedule tasks to run'), diff --git a/installer/data/mysql/es-ES/mandatory/userpermissions.sql b/installer/data/mysql/es-ES/mandatory/userpermissions.sql index ec61ea0..ce96ec1 100644 --- a/installer/data/mysql/es-ES/mandatory/userpermissions.sql +++ b/installer/data/mysql/es-ES/mandatory/userpermissions.sql @@ -28,6 +28,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'), (13, 'export_catalog', 'Export bibliographic and holdings data'), (13, 'import_patrons', 'Import patron data'), + (13, 'edit_patrons', 'Perform batch modification of patrons'), (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'), (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'), (13, 'schedule_tasks', 'Schedule tasks to run'), diff --git a/installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql b/installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql index faaaf39..7a30f82 100644 --- a/installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql +++ b/installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql @@ -18,6 +18,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES (13, 'manage_staged_marc', 'Gérer les notices du réservoir, les charger ou annuler leur chargement'), (13, 'export_catalog', 'Exporter des notices bibliographiques et leurs exemplaires'), (13, 'import_patrons', 'Importer des données d''adhérents'), + (13, 'edit_patrons', 'Modification par lot des lecteurs'), (13, 'delete_anonymize_patrons', 'Supprimer les anciens adhérents et anonymiser l''historique des prêts (supprime l''historique des prêts des lecteurs'), (13, 'batch_upload_patron_images', 'Charger sur le serveur les images des adhérents par lot ou un par un'), (13, 'schedule_tasks', 'Planifier les tâches à exécuter'), diff --git a/installer/data/mysql/it-IT/necessari/userpermissions.sql b/installer/data/mysql/it-IT/necessari/userpermissions.sql index 926b47c..fd7cb12 100644 --- a/installer/data/mysql/it-IT/necessari/userpermissions.sql +++ b/installer/data/mysql/it-IT/necessari/userpermissions.sql @@ -30,6 +30,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES (13, 'manage_staged_marc', 'Gestisci i record MARC in lavorazione, inclusi il completare e il cancellare gli import'), (13, 'export_catalog', 'Esporta i dati bibliografici e di copia'), (13, 'import_patrons', 'Importa i dati utente'), + (13, 'edit_patrons', 'Perform batch modification of patrons'), (13, 'delete_anonymize_patrons', 'Cancella i vecchi prestiti e rendi anonimo lo storico della circolazione (canella in lettura lo storico utenti prestito)'), (13, 'batch_upload_patron_images', 'Aggiorna le foto utente in modalità batch o al momento'), (13, 'schedule_tasks', 'Schedula i task da far andare'), diff --git a/installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql b/installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql index 24f081e..8525a20 100644 --- a/installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql +++ b/installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql @@ -49,6 +49,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES (13, 'manage_staged_marc', 'Behandle lagrede MARC-poster, inkludert ferdigstilling og reversering av importer'), (13, 'export_catalog', 'Eksportere bibliografiske data og beholdningsdata'), (13, 'import_patrons', 'Importere låneropplysninger'), + (13, 'edit_patrons', 'Perform batch modification of patrons'), (13, 'delete_anonymize_patrons', 'Slette utgåtte lånere og anonymisere lånehistorikk'), (13, 'batch_upload_patron_images', 'Laste opp bilder av lånere enkeltvis eller en masse'), (13, 'schedule_tasks', 'Planlegge oppgaver som skal kjøres'), diff --git a/installer/data/mysql/pl-PL/mandatory/userpermissions.sql b/installer/data/mysql/pl-PL/mandatory/userpermissions.sql index f16a14d..a46ddfe 100644 --- a/installer/data/mysql/pl-PL/mandatory/userpermissions.sql +++ b/installer/data/mysql/pl-PL/mandatory/userpermissions.sql @@ -28,6 +28,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES (13, 'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'), (13, 'export_catalog', 'Export bibliographic and holdings data'), (13, 'import_patrons', 'Import patron data'), + (13, 'edit_patrons', 'Perform batch modification of patrons'), (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'), (13, 'batch_upload_patron_images', 'Upload patron images in batch or one at a time'), (13, 'schedule_tasks', 'Schedule tasks to run'), diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 9225c32..1aacd81 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -5086,6 +5086,16 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { SetVersion($DBversion); } + + + +$DBversion = "3.07.00.XXX"; +if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { + $dbh->do("INSERT IGNORE INTO `permissions` (`module_bit`, `code`, `description`) VALUES('13', 'edit_patrons', 'Perform batch modifivation of patrons')"); + print "Upgrade to $DBversion done (Adds permissions flag for access to the patron modifications tool)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 DropAllForeignKeys($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt new file mode 100644 index 0000000..c363181 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt @@ -0,0 +1,310 @@ +[% USE KohaDates %] +[% INCLUDE 'doc-head-open.inc'%] +Koha › Tools › [% IF ( del ) %]Batch item deletion[% ELSE %]Batch item modification[% END %] +[% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'calendar.inc' %] + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
+
+
+
+ [% IF ( op == 'show_form' ) %] +

Batch patrons modification

+
+
+ Use a file + +
+
+ Or list cardnumbers one by one +
    +
  1. + + +
  2. +
+
+ +
+ + Cancel +
+
+ [% END %] + + [% IF ( op == 'show' or op == 'show_results' ) %] + [% IF ( op == 'show' ) %] +

Batch patrons modification

+ [% ELSE %] +

Batch patrons results

+ [% END %] + [% IF ( notfoundcardnumbers ) %] +

Warning, the following cardnumbers were not found:

+ + + + + + [% FOREACH notfoundcardnumber IN notfoundcardnumbers %] + + [% END %] + +
Cardnumbers not found
[% notfoundcardnumber.cardnumber %]
+ [% END %] + + [% IF ( op == 'show_results' ) %] + [% IF ( errors ) %] + Errors occured : +
    + [% FOREACH error IN errors %] + [% IF ( error.error == 'can_not_update' ) %] +
  • Can not update borrower with borrowernumber [% error.borrowernumber %]
  • + [% ELSE %] +
  • [% error.error %]
  • + [% END %] + [% END %] +
+ [% END %] +
+ [% END %] + + [% IF ( op == 'show' ) %] +
+ + [% IF ( borrowers ) %] + + [% END %] + [% END %] +
+
+ + + + [% IF ( op == 'show' ) %] + + [% END %] + + + + + + + + + [% FOREACH attrh IN attributes_header %] + + [% END %] + + + + [% FOREACH borrower IN borrowers %] + + [% IF ( op == 'show' ) %] + + [% END %] + + + + + + + + + [% FOREACH pa IN borrower.patron_attributes %] + [% IF ( pa.code ) %] + + [% ELSE %] + + [% END %] + [% END %] + + [% END %] + +
 SurnameFirstnameBranchnameCategorycodeCardnumberdateenrolleddateexpirydebarred[% attrh.attribute %]
[% borrower.surname %][% borrower.firstname %][% borrower.branchname %][% borrower.categorycode %][% borrower.cardnumber %][% borrower.dateenrolled | $KohaDates %][% borrower.dateexpiry | $KohaDates %][% borrower.debarred | $KohaDates %][% pa.code %]=[% pa.value %]
+
+
+ + [% IF ( op == 'show' ) %] +
+

Edit Patrons

+
Checking the box right next the label will disable the entry and delete the values of that field on all selected patrons
+
+
    + [% FOREACH field IN fields %] +
  1. + + + [% IF ( field.type == 'text' ) %] + + [% END %] + [% IF ( field.type == 'select' ) %] + [% IF field.option.size %] + + [% ELSE %] + There is no value defined for [% field.name %] + [% END %] + [% END %] + [% IF ( field.type == 'date' ) %] + Show Calendar + + X + + [% END %] +
  2. + [% END %] +
  3. + + + + + + +
  4. +
+
+
+ + Cancel +
+
+
+ [% END %] + [% END %] + [% IF ( op == 'show_results' ) %] +
+ new Batch patrons modification + [% END %] +
+
+
+ [% INCLUDE 'tools-menu.inc' %] +
+
+
+ + + + diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt index 0cd163d..58400d8 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt @@ -45,6 +45,11 @@
Delete old borrowers and anonymize circulation history (deletes borrower reading history)
[% END %] + [% IF ( CAN_user_tools_edit_patrons ) %] +
Patrons (Modification)
+
Modify patrons
+ [% END %] + [% IF ( CAN_user_tools_moderate_tags ) %]
Tags [% IF ( pendingtags ) %][% pendingtags %][% END %]
Moderate patron tags
diff --git a/tools/modborrowers.pl b/tools/modborrowers.pl new file mode 100755 index 0000000..6dac4e8 --- /dev/null +++ b/tools/modborrowers.pl @@ -0,0 +1,322 @@ +#!/usr/bin/perl + +# Copyright 2012 BibLibre +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; +use CGI; +use C4::Auth; +use C4::Branch; +use C4::Koha; +use C4::Members; +use C4::Members::Attributes qw(GetBorrowerAttributes UpdateBorrowerAttribute DeleteBorrowerAttribute); +use C4::Members::AttributeTypes qw/GetAttributeTypes_hashref/; +use C4::Output; +use List::MoreUtils qw /any uniq/; + +my $input = new CGI; +my $op = $input->param('op') || 'show_form'; +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { template_name => "tools/modborrowers.tmpl", + query => $input, + type => "intranet", + authnotrequired => 0, + flagsrequired => { tools => "edit_patrons" }, + } +); + +my %cookies = parse CGI::Cookie($cookie); +my $sessionID = $cookies{'CGISESSID'}->value; +my $dbh = C4::Context->dbh; + + + +if ( $op eq 'show' ) { + my $filefh = $input->upload('uploadfile'); + my $filecontent = $input->param('filecontent'); + my @borrowers; + my @cardnumbers; + my @notfoundcardnumbers; + + my @contentlist; + if ($filefh) { + while ( my $content = <$filefh> ) { + $content =~ s/[\r\n]*$//g; + push @cardnumbers, $content if $content; + } + } else { + if ( my $list = $input->param('cardnumberlist') ) { + push @cardnumbers, split( /\s\n/, $list ); + } + } + + my $max_nb_attr = 0; + for my $cardnumber ( @cardnumbers ) { + my $borrower = GetBorrowerInfos( cardnumber => $cardnumber ); + if ( $borrower ) { + $max_nb_attr = scalar( @{ $borrower->{patron_attributes} } ) + if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr; + push @borrowers, $borrower; + } else { + push @notfoundcardnumbers, $cardnumber; + } + } + + # Just for a correct display + for my $borrower ( @borrowers ) { + my $length = scalar( @{ $borrower->{patron_attributes} } ); + push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1); + } + + my @patron_attributes_values; + my @patron_attributes_codes; + my $patron_attribute_types = C4::Members::AttributeTypes::GetAttributeTypes_hashref('all'); + my $patron_categories = C4::Members::GetBorrowercategoryList; + for ( values $patron_attribute_types ) { + my $attr_type = C4::Members::AttributeTypes->fetch( $_->{code} ); + my $options = $attr_type->authorised_value_category + ? GetAuthorisedValues( $attr_type->authorised_value_category ) + : undef; + push @patron_attributes_values, + { + attribute_code => $_->{code}, + options => $options, + }; + + my $category_code = $_->{category_code}; + my ( $category_lib ) = map { + ( defined $category_code and $_->{categorycode} eq $category_code ) ? $_->{description} : () + } @$patron_categories; + push @patron_attributes_codes, + { + attribute_code => $_->{code}, + attribute_lib => $_->{description}, + category_lib => $category_lib, + type => $attr_type->authorised_value_category ? 'select' : 'text', + }; + } + + my @attributes_header = (); + for ( 1 .. scalar( $max_nb_attr ) ) { + push @attributes_header, { attribute => "Attributes $_" }; + } + $template->param( borrowers => \@borrowers ); + $template->param( attributes_header => \@attributes_header ); + @notfoundcardnumbers = map { { cardnumber => $_ } } @notfoundcardnumbers; + $template->param( notfoundcardnumbers => \@notfoundcardnumbers ) + if @notfoundcardnumbers; + + my $branches = GetBranchesLoop; + my @branches_option; + push @branches_option, { value => $_->{value}, lib => $_->{branchname} } for @$branches; + unshift @branches_option, { value => "", lib => "" }; + my $categories = GetBorrowercategoryList; + my @categories_option; + push @categories_option, { value => $_->{categorycode}, lib => $_->{description} } for @$categories; + unshift @categories_option, { value => "", lib => "" }; + my $bsort1 = GetAuthorisedValues("Bsort1"); + my @sort1_option; + push @sort1_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort1; + unshift @sort1_option, { value => "", lib => "" } + if @sort1_option; + my $bsort2 = GetAuthorisedValues("Bsort2"); + my @sort2_option; + push @sort2_option, { value => $_->{authorised_value}, lib => $_->{lib} } for @$bsort2; + unshift @sort2_option, { value => "", lib => "" } + if @sort2_option; + my @fields = ( + { + name => "surname", + lib => "Surname", + type => "text", + } + , + { + name => "firstname", + lib => "Firstname", + type => "text", + } + , + { + name => "branchcode", + lib => "Branchname", + type => "select", + option => \@branches_option, + } + , + { + name => "categorycode", + lib => "Category", + type => "select", + option => \@categories_option, + } + , + { + name => "sort1", + lib => "Sort 1", + type => "select", + option => \@sort1_option, + } + , + { + name => "sort2", + lib => "Sort 2", + type => "select", + option => \@sort2_option, + } + , + { + name => "dateenrolled", + lib => "Date enrolled", + type => "date", + } + , + { + name => "dateexpiry", + lib => "Date expiry", + type => "date", + } + , + { + name => "debarred", + lib => "Debarred", + type => "date", + } + , + { + name => "debarredcomment", + lib => "Debarred comment", + type => "text", + } + , + { + name => "borrowernotes", + lib => "Borrower Notes", + type => "text", + } + ); + + $template->param('patron_attributes_codes', \@patron_attributes_codes); + $template->param('patron_attributes_values', \@patron_attributes_values); + + $template->param( fields => \@fields ); + $template->param( DHTMLcalendar_dateformat => C4::Dates->DHTMLcalendar() ); +} + +if ( $op eq 'do' ) { + + my @disabled = $input->param('disable_input'); + my $infos; + for my $field ( qw/surname firstname branchcode categorycode sort1 sort2 dateenrolled dateexpiry debarred debarredcomment borrowernotes/ ) { + my $value = $input->param($field); + $infos->{$field} = $value if $value; + $infos->{$field} = "" if grep { /^$field$/ } @disabled; + } + + my @attributes = $input->param('patron_attributes'); + my @attr_values = $input->param('patron_attributes_value'); + + my @errors; + my @borrowernumbers = $input->param('borrowernumber'); + for my $borrowernumber ( @borrowernumbers ) { + if ( defined $infos ) { + $infos->{borrowernumber} = $borrowernumber; + my $success = ModMember(%$infos); + push @errors, { error => "can_not_update", borrowernumber => $infos->{borrowernumber} } if not $success; + } + + my $borrower_categorycode = GetBorrowerCategorycode $borrowernumber; + my $i=0; + for ( @attributes ) { + my $attribute; + $attribute->{code} = $_; + $attribute->{attribute} = $attr_values[$i]; + my $attr_type = C4::Members::AttributeTypes->fetch( $_ ); + ++$i and next if $attr_type->{category_code} and $attr_type->{category_code} ne $borrower_categorycode; + my $valuename = "attr" . $i . "_value"; + if ( grep { /^$valuename$/ } @disabled ) { + eval { + DeleteBorrowerAttribute $borrowernumber, $attribute; + }; + push @errors, { error => $@ } if $@; + } else { + ++$i and next if not $attribute->{attribute}; + eval { + UpdateBorrowerAttribute $borrowernumber, $attribute; + }; + push @errors, { error => $@ } if $@; + } + $i++; + } + } + $op = "show_results"; + + my @borrowers; + my $max_nb_attr = 0; + for my $borrowernumber ( @borrowernumbers ) { + my $borrower = GetBorrowerInfos( borrowernumber => $borrowernumber ); + if ( $borrower ) { + $max_nb_attr = scalar( @{ $borrower->{patron_attributes} } ) + if scalar( @{ $borrower->{patron_attributes} } ) > $max_nb_attr; + push @borrowers, $borrower; + } + } + my @patron_attributes_option; + for my $borrower ( @borrowers ) { + push @patron_attributes_option, { value => "$_->{code}", lib => $_->{code} } for @{ $borrower->{patron_attributes} }; + my $length = scalar( @{ $borrower->{patron_attributes} } ); + push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1); + } + + my @attributes_header = (); + for ( 1 .. scalar( $max_nb_attr ) ) { + push @attributes_header, { attribute => "Attributes $_" }; + } + + $template->param( borrowers => \@borrowers ); + $template->param( attributes_header => \@attributes_header ); + + $template->param( borrowers => \@borrowers ); + $template->param( errors => \@errors ); +} + +$template->param( + op => $op, +); +output_html_with_http_headers $input, $cookie, $template->output; +exit; + +sub GetBorrowerInfos { + my ( %info ) = @_; + my $borrower = GetMember( %info ); + if ( $borrower ) { + $borrower->{branchname} = GetBranchName( $borrower->{branchcode} ); + for ( qw(dateenrolled dateexpiry debarred) ) { + my $userdate = $borrower->{$_}; + unless ($userdate && $userdate ne "0000-00-00" and $userdate ne "9999-12-31") { + $borrower->{$_} = ''; + next; + } + $borrower->{$_} = $userdate || ''; + } + $borrower->{category_description} = GetBorrowercategory( $borrower->{categorycode} )->{description}; + my $attr_loop = C4::Members::Attributes::GetBorrowerAttributes( $borrower->{borrowernumber} ); + $borrower->{patron_attributes} = $attr_loop; + } + return $borrower; +} + -- 1.7.7.3