Bugzilla – Attachment 8708 Details for
Bug 5742
batch edit patrons
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
But 5742 Batch edit patrons
0001-But-5742-Batch-edit-patrons.patch (text/plain), 49.04 KB, created by
Jonathan Druart
on 2012-03-30 08:17:49 UTC
(
hide
)
Description:
But 5742 Batch edit patrons
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2012-03-30 08:17:49 UTC
Size:
49.04 KB
patch
obsolete
>From bd0e13f0e0841398253ac6371208b2c2772732fd Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@biblibre.com> >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 | 159 +++++---- > C4/Members/AttributeTypes.pm | 2 +- > 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 | 7 + > .../prog/en/modules/tools/modborrowers.tt | 312 ++++++++++++++++++ > .../prog/en/modules/tools/tools-home.tt | 5 + > tools/modborrowers.pl | 342 ++++++++++++++++++++ > 14 files changed, 813 insertions(+), 77 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..384e31a 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 >@@ -329,7 +330,7 @@ sub GetMemberDetails { > $sth->execute($cardnumber); > } > else { >- return undef; >+ return; > } > my $borrower = $sth->fetchrow_hashref; > my ($amount) = GetMemberAccountRecords( $borrowernumber); >@@ -581,7 +582,7 @@ sub GetMemberRelatives { > $sth->execute($borrowernumber); > my $data = $sth->fetchrow_arrayref(); > push @glist, $data->[0] if $data->[0]; >- my $guarantor = $data->[0] if $data->[0]; >+ my $guarantor = $data->[0] ? $data->[0] : undef; > > # Getting guarantees > $query = "SELECT borrowernumber FROM borrowers WHERE guarantorid=?"; >@@ -692,7 +693,7 @@ sub GetMemberIssuesAndFines { > return ($overdue_count, $issue_count, $total_fines); > } > >-sub columns(;$) { >+sub columns { > return @{C4::Context->dbh->selectcol_arrayref("SHOW columns from borrowers")}; > } > >@@ -846,7 +847,7 @@ mode, to avoid database corruption. > use vars qw( @weightings ); > my @weightings = ( 8, 4, 6, 3, 5, 2, 1 ); > >-sub fixup_cardnumber ($) { >+sub fixup_cardnumber { > my ($cardnumber) = @_; > my $autonumber_members = C4::Context->boolean_preference('autoMemberNum') || 0; > >@@ -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/AttributeTypes.pm b/C4/Members/AttributeTypes.pm >index 8c96e54..d8d5508 100644 >--- a/C4/Members/AttributeTypes.pm >+++ b/C4/Members/AttributeTypes.pm >@@ -151,7 +151,7 @@ sub fetch { > $sth->execute($code); > my $row = $sth->fetchrow_hashref; > $sth->finish(); >- return undef unless defined $row; >+ return unless defined $row; > > $self->{'code'} = $row->{'code'}; > $self->{'description'} = $row->{'description'}; >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 ddc288c..9cecd2f 100755 >--- a/installer/data/mysql/updatedatabase.pl >+++ b/installer/data/mysql/updatedatabase.pl >@@ -5109,6 +5109,13 @@ 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..9205e8f >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt >@@ -0,0 +1,312 @@ >+[% USE KohaDates %] >+[% INCLUDE 'doc-head-open.inc'%] >+<title>Koha › Tools › [% IF ( del ) %]Batch item deletion[% ELSE %]Batch item modification[% END %] </title> >+[% INCLUDE 'doc-head-close.inc' %] >+[% INCLUDE 'calendar.inc' %] >+<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.tablesorter.min.js"></script> >+<script type="text/JavaScript" language="JavaScript"> >+//<![CDATA[ >+ var patron_attributes_lib = new Array(); >+ var patron_attributes_values = new Array(); >+ $(document).ready(function() { >+ $("#borrowerst").tablesorter(); >+ >+ $("#selectallbutton").click(function() { >+ $("#borrowerst").find("input:checkbox").each(function() { >+ $(this).attr("checked", true); >+ }); >+ return false; >+ }); >+ $("#clearallbutton").click(function() { >+ $("#borrowerst").find("input:checkbox").each(function() { >+ $(this).attr("checked", false); >+ }); >+ return false; >+ }); >+ >+ var values = new Array(); >+ var lib = new Array(); >+ [% FOREACH pav IN patron_attributes_values %] >+ values = new Array(); >+ lib = new Array(); >+ [% FOREACH option IN pav.options %] >+ values.push("[% option.lib %]"); >+ lib.push("[% option.authorised_value %]"); >+ [% END %] >+ patron_attributes_lib["[% pav.attribute_code %]"] = values; >+ patron_attributes_values["[% pav.attribute_code %]"] = lib; >+ [% END %] >+ >+ $('select[name="patron_attributes"]').change(function() { >+ updateAttrValues(this); >+ } ); >+ >+ $('select[name="patron_attributes"]').change(); >+ >+ } ); >+ >+ function updateAttrValues (select_attr) { >+ var attr_code = $(select_attr).val(); >+ var type = $(select_attr).find("option:selected").attr('data-type'); >+ var category = $(select_attr).find("option:selected").attr('data-category'); >+ var span = $(select_attr).parent().parent().find('span.patron_attributes_value'); >+ var information_category_node = $(select_attr).parent().parent().find('span.information_category'); >+ information_category_node.html(""); >+ if ( category.length > 0 ) { >+ information_category_node.html('This attribute will be only applied to the borrower\'s category "' + category + '"'); >+ } >+ if ( type == 'select' ) { >+ var options = '<option value = ""></option>'; >+ for ( var i = 0 ; i < patron_attributes_values[attr_code].length ; i++ ) { >+ options += '<option value="'+patron_attributes_values[attr_code][i]+'">'+patron_attributes_lib[attr_code][i]+'</option>'; >+ } >+ span.html('<select name="patron_attributes_value">' + options + '</select>'); >+ } else { >+ span.html('<input type="text" name="patron_attributes_value"/>') >+ } >+ } >+ >+ function add_attributes() { >+ var li_node = $("li.attributes:last"); >+ var li_clone = $(li_node).clone(); >+ if ( $(li_clone).find("a.delete").length == 0 ) { >+ $(li_clone).append('[<a href="#" title="Delete" class="delete" onclick="del_attributes(this);return false;">X</a>]'); >+ } >+ $(li_clone).find('select[name="patron_attributes"]').change(function() { >+ updateAttrValues(this); >+ } ); >+ >+ $(li_clone).find('select[name="patron_attributes"]').change(); >+ >+ $("#fields_list>ol").append(li_clone); >+ update_attr_values(); >+ } >+ >+ function del_attributes(a_node) { >+ $(a_node).parent('li').remove(); >+ update_attr_values(); >+ } >+ >+ function update_attr_values() { >+ $("li.attributes").each(function(i) { >+ $(this).find("input:checkbox").val("attr"+i+"_value"); >+ }); >+ } >+ function clearDate(nodeid) { >+ $("#"+nodeid).val(""); >+ } >+ >+//]]> >+</script> >+</head> >+<body> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> › >+ <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> › >+ <a href="/cgi-bin/koha/tools/modborrowers.pl">Patrons modification</a> >+</div> >+ >+<div id="doc3" class="yui-t2"> >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ [% IF ( op == 'show_form' ) %] >+ <h1>Batch patrons modification</h1> >+ <form method="post" enctype="multipart/form-data" action="/cgi-bin/koha/tools/modborrowers.pl"> >+ <fieldset class="rows"> >+ <legend>Use a file</legend> >+ <label for="uploadfile">File: </label> <input type="file" id="uploadfile" name="uploadfile" /> >+ </fieldset> >+ <fieldset class="rows"> >+ <legend>Or list cardnumbers one by one</legend> >+ <ol> >+ <li> >+ <label for="cardnumberlist">Carnumber list (one cardnumber per line): </label> >+ <textarea rows="10" cols="30" id="cardnumberlist" name="cardnumberlist">[% cardnumberlist %]</textarea> >+ </li> >+ </ol> >+ </fieldset> >+ <input type="hidden" name="op" value="show" /> >+ <fieldset class="action"> >+ <input type="submit" value="Continue" class="button" /> >+ <a class="cancel" href="/cgi-bin/koha/tools/tools-home.pl">Cancel</a> >+ </fieldset> >+ </form> >+ [% END %] >+ >+ [% IF ( op == 'show' or op == 'show_results' ) %] >+ [% IF ( op == 'show' ) %] >+ <h1>Batch patrons modification</h1> >+ [% ELSE %] >+ <h1>Batch patrons results</h1> >+ [% END %] >+ [% IF ( notfoundcardnumbers ) %] >+ <div class="dialog alert"><p>Warning, the following cardnumbers were not found:</p></div> >+ <table style="margin:auto;"> >+ <thead> >+ <tr><th>Cardnumbers not found</th></tr> >+ </thead> >+ <tbody> >+ [% FOREACH notfoundcardnumber IN notfoundcardnumbers %] >+ <tr><td>[% notfoundcardnumber.cardnumber %]</td></tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% END %] >+ >+ [% IF ( op == 'show_results' ) %] >+ [% IF ( errors ) %] >+ Errors occured : >+ <ul class="warnings"> >+ [% FOREACH error IN errors %] >+ [% IF ( error.error == 'can_not_update' ) %] >+ <li>Can not update borrower with borrowernumber [% error.borrowernumber %]</li> >+ [% ELSE %] >+ <li>[% error.error %]</li> >+ [% END %] >+ [% END %] >+ </ul> >+ [% END %] >+ <br/> >+ [% END %] >+ >+ [% IF ( op == 'show' ) %] >+ <form name="f" action="modborrowers.pl" method="post"> >+ <input type="hidden" name="op" value="do" /> >+ [% IF ( borrowers ) %] >+ <div id="toolbar"><a id="selectallbutton" href="#">Select All</a> | <a id="clearallbutton" href="#">Clear All</a></div> >+ [% END %] >+ [% END %] >+ <div id="cataloguing_additem_itemlist"> >+ <div style="overflow:auto"> >+ <table id="borrowerst"> >+ <thead> >+ <tr> >+ [% IF ( op == 'show' ) %] >+ <th> </th> >+ [% END %] >+ <th>Surname</th> >+ <th>Firstname</th> >+ <th>Branchname</th> >+ <th>Categorycode</th> >+ <th>Cardnumber</th> >+ <th>dateenrolled</th> >+ <th>dateexpiry</th> >+ <th>debarred</th> >+ [% FOREACH attrh IN attributes_header %] >+ <th>[% attrh.attribute %]</th> >+ [% END %] >+ </tr> >+ </thead> >+ <tbody> >+ [% FOREACH borrower IN borrowers %] >+ <tr> >+ [% IF ( op == 'show' ) %] >+ <td><input type="checkbox" name="borrowernumber" value="[% borrower.borrowernumber %]" checked="checked" /></td> >+ [% END %] >+ <td>[% borrower.surname %]</td> >+ <td>[% borrower.firstname %]</td> >+ <td>[% borrower.branchname %]</td> >+ <td>[% borrower.categorycode %]</td> >+ <td>[% borrower.cardnumber %]</td> >+ <td>[% borrower.dateenrolled | $KohaDates %]</td> >+ <td>[% borrower.dateexpiry | $KohaDates %]</td> >+ <td>[% borrower.debarred | $KohaDates %]</td> >+ [% FOREACH pa IN borrower.patron_attributes %] >+ [% IF ( pa.code ) %] >+ <td>[% pa.code %]=[% pa.value %]</td> >+ [% ELSE %] >+ <td></td> >+ [% END %] >+ [% END %] >+ </tr> >+ [% END %] >+ </tbody> >+ </table> >+ </div> >+ </div> >+ >+ [% IF ( op == 'show' ) %] >+ <div id="cataloguing_additem_newitem"> >+ <h2>Edit Patrons</h2> >+ <div class="hint">Checking the box right next the label will disable the entry and delete the values of that field on all selected patrons</div> >+ <fieldset class="rows" id="fields_list"> >+ <ol> >+ [% FOREACH field IN fields %] >+ <li> >+ <label style="width:20em;">[% field.lib %]</label> >+ <input type="checkbox" title="check to delete this field" name="disable_input" value="[% field.name %]"/> >+ [% IF ( field.type == 'text' ) %] >+ <input type="text" name="[% field.name %]" value="" /> >+ [% END %] >+ [% IF ( field.type == 'select' ) %] >+ [% IF field.option.size %] >+ <select name="[% field.name %]" > >+ [% FOREACH opt IN field.option %] >+ <option value="[% opt.value %]">[% opt.lib %]</option> >+ [% END %] >+ </select> >+ [% ELSE %] >+ There is no value defined for [% field.name %] >+ [% END %] >+ [% END %] >+ [% IF ( field.type == 'date' ) %] >+ <img src="[% themelang %]/lib/calendar/cal.gif" style="cursor: pointer;" alt="Show Calendar" title="Show Calendar" id="[% field.name %]button"/> >+ <input type="text" name="[% field.name %]" id="[% field.name %]" value="" size="10" maxlength="10" readonly /> >+ <a href="#" onclick="clearDate('[% field.name %]');return false;">X</a> >+ <script type="text/javascript"> >+ //<![CDATA[ >+ Calendar.setup({ >+ inputField : "[% field.name %]", >+ button : "[% field.name %]button", >+ ifFormat : "[% DHTMLcalendar_dateformat %]", >+ onClose: function() { $("#[% field.name %]").change(); this.hide();} >+ }); >+ //]]> >+ </script> >+ [% END %] >+ </li> >+ [% END %] >+ [% IF ( patron_attributes_codes ) %] >+ <li class="attributes"> >+ <label style="width:20em;">Attribute >+ <select name="patron_attributes"> >+ [% FOREACH pac IN patron_attributes_codes %] >+ <option value="[% pac.attribute_code %]" data-type="[% pac.type %]" data-category="[% pac.category_lib %]">[% pac.attribute_lib %]</option> >+ [% END %] >+ </select> >+ </label> >+ <input type="checkbox" title="check to delete this field" name="disable_input" value="attr0_value" /> >+ <span class="patron_attributes_value"></span> >+ <a href="#" title="Add an attribute" onclick="add_attributes(); return false;">+</a> >+ <span class="information_category"></span> >+ </li> >+ [% END %] >+ </ol> >+ </fieldset> >+ <fieldset class="action"> >+ <input type="submit" name="mainformsubmit" value="Save" /> >+ <a href="/cgi-bin/koha/tools/modborrowers.pl" class="cancel">Cancel</a> >+ </fieldset> >+ </div> >+ </form> >+ [% END %] >+ [% END %] >+ [% IF ( op == 'show_results' ) %] >+ <br/> >+ <a href="/cgi-bin/koha/tools/modborrowers.pl" title="new Batch patrons modification">new Batch patrons modification</a> >+ [% END %] >+ </div> >+ </div> >+ <div class="yui-b"> >+ [% INCLUDE 'tools-menu.inc' %] >+ </div> >+ </div> >+ </div> >+</div> >+</body> >+</html> >+ >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 @@ > <dd>Delete old borrowers and anonymize circulation history (deletes borrower reading history)</dd> > [% END %] > >+ [% IF ( CAN_user_tools_edit_patrons ) %] >+ <dt><a href="/cgi-bin/koha/tools/modborrowers.pl">Patrons (Modification)</a></dt> >+ <dd>Modify patrons</dd> >+ [% END %] >+ > [% IF ( CAN_user_tools_moderate_tags ) %] > <dt><a href="/cgi-bin/koha/tags/review.pl">Tags</a> [% IF ( pendingtags ) %]<span class="holdcount"><a href="/cgi-bin/koha/tags/review.pl">[% pendingtags %]</a></span>[% END %]</dt> > <dd>Moderate patron tags</dd> >diff --git a/tools/modborrowers.pl b/tools/modborrowers.pl >new file mode 100755 >index 0000000..dad1797 >--- /dev/null >+++ b/tools/modborrowers.pl >@@ -0,0 +1,342 @@ >+#!/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. >+ >+# modborrowers.pl >+# >+# Batch Edit Patrons >+# Modification for patron's fields: >+# surname firstname branchcode categorycode sort1 sort2 dateenrolled dateexpiry debarred debarredcomment borrowernotes >+# And for patron attributes. >+ >+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; >+ >+ >+ >+# Show borrower informations >+if ( $op eq 'show' ) { >+ my $filefh = $input->upload('uploadfile'); >+ my $filecontent = $input->param('filecontent'); >+ my @borrowers; >+ my @cardnumbers; >+ my @notfoundcardnumbers; >+ >+ # Get cardnumbers from a file or the input area >+ 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); >+ } >+ >+ # Construct the patron attributes list >+ 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; >+ >+ # Construct drop-down list values >+ 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() ); >+} >+ >+# Process modifications >+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 each borrower selected >+ for my $borrowernumber ( @borrowernumbers ) { >+ # If at least one field are filled, we want to modify the borrower >+ 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( $_ ); >+ # If this borrower is not in the category of this attribute, we don't want to modify this attribute >+ ++$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 ) { >+ # The attribute is disabled, we remove it for this borrower ! >+ eval { >+ DeleteBorrowerAttribute $borrowernumber, $attribute; >+ }; >+ push @errors, { error => $@ } if $@; >+ } else { >+ # Attribute's value is empty, we don't want to modify it >+ ++$i and next if not $attribute->{attribute}; >+ >+ eval { >+ UpdateBorrowerAttribute $borrowernumber, $attribute; >+ }; >+ push @errors, { error => $@ } if $@; >+ } >+ $i++; >+ } >+ } >+ $op = "show_results"; # We have process modifications, the user want to view its >+ >+ # Construct the results list >+ 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 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 5742
:
8687
|
8696
|
8708
|
8709
|
8801
|
8867
|
8876
|
8903
|
9149
|
9150