From 8a3b76168e29f1c3fab1329496537b8792062600 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Wed, 10 Jul 2013 09:38:40 -0400 Subject: [PATCH] Bug 10565 - Add a "Patron List" feature for storing and manipulating collections of patrons The patron lists feature is somewhat similar to the record lists feature in that it allows a librarian to create a list of patrons for later retrieval and manipluation. These lists can then be used with the batch patron modification tool. Test Plan: 0) Apply the patch for Bug 8798 1) Apply this patch 2) Run updatedatabase.pl 3) Access the patron lists feature from Koha's Tools menu. 4) Create a new list via the "New patron list" button. 5) For this list, click the "Edit" button, and change the list name. 6) For this list, click the "Add patrons" button, and search for and add some patrons to your list. 7) For this list select some patrons to remove them. 8) Try both adding some new patrons, and removing some old patrons as a single action. 9) Click the "Patrons" link on the Koha toolbar 10) Search the patrons, or browse by letter to get patron results 11) Check the checkboxes next to one or more patrons, and add the selected patrons to your existing list. 12) Change the "Selected patrons" pulldown to "All resultant patrons" and add them to your list. 13) Check the checkboxes next to one or more patrons, and add the selected patrons to a new list. 14) Try manipulating a list of patrons using the batch patron modification tool. 15) Go back to the Patron Lists feature and delete your lists. 16) Run 'prove t/db_dependent/PatronLists.t' Signed-off-by: Nora Blake --- Koha/List/Patron.pm | 222 ++++++++++++++++++++ Koha/Schema/Result/PatronList.pm | 90 ++++++++ Koha/Schema/Result/PatronListPatron.pm | 90 ++++++++ installer/data/mysql/kohastructure.sql | 41 ++++ installer/data/mysql/updatedatabase.pl | 39 ++++ .../prog/en/modules/members/member.tt | 129 +++++++++++- .../prog/en/modules/patron_lists/add-modify.tt | 56 +++++ .../prog/en/modules/patron_lists/list.tt | 132 ++++++++++++ .../prog/en/modules/patron_lists/lists.tt | 74 +++++++ .../prog/en/modules/tools/modborrowers.tt | 26 ++- .../prog/en/modules/tools/tools-home.tt | 5 +- members/member.pl | 70 +++++-- patron_lists/add-modify.pl | 61 ++++++ patron_lists/delete.pl | 43 ++++ patron_lists/list.pl | 54 +++++ patron_lists/lists.pl | 43 ++++ patron_lists/patrons.pl | 59 +++++ t/db_dependent/PatronLists.t | 75 +++++++ tools/modborrowers.pl | 18 ++- 19 files changed, 1295 insertions(+), 32 deletions(-) create mode 100644 Koha/List/Patron.pm create mode 100644 Koha/Schema/Result/PatronList.pm create mode 100644 Koha/Schema/Result/PatronListPatron.pm create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/add-modify.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/list.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/lists.tt create mode 100755 patron_lists/add-modify.pl create mode 100755 patron_lists/delete.pl create mode 100755 patron_lists/list.pl create mode 100755 patron_lists/lists.pl create mode 100755 patron_lists/patrons.pl create mode 100755 t/db_dependent/PatronLists.t diff --git a/Koha/List/Patron.pm b/Koha/List/Patron.pm new file mode 100644 index 0000000..2656b86 --- /dev/null +++ b/Koha/List/Patron.pm @@ -0,0 +1,222 @@ +package Koha::List::Patron; + +# Copyright 2013 ByWater Solutions +# +# 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. + +=head1 NAME + +Koha::List::Patron - Managment of lists of patrons + +=head1 FUNCTIONS + +=cut + +use Modern::Perl; + +use Carp; + +use Koha::Database; + +use base 'Exporter'; +our @EXPORT = ( + qw( + GetPatronLists + + DelPatronList + AddPatronList + ModPatronList + + AddPatronsToList + DelPatronsFromList + ) +); + +=head2 GetPatronLists + + my @lists = GetPatronLists( $params ); + + Returns an array of lists created by the the given user + or the logged in user if none is passed in. +=cut + +sub GetPatronLists { + my ($params) = @_; + + $params->{owner} ||= C4::Context->userenv->{'number'}; + + unless ( $params->{owner} ) { + carp("No owner passed in or defined!"); + return; + } + + delete( $params->{owner} ) if ( C4::Context->IsSuperLibrarian() ); + + my $schema = Koha::Database->new()->schema(); + + my @patron_lists = $schema->resultset('PatronList')->search($params); + + return wantarray() ? @patron_lists : \@patron_lists; +} + +=head2 DelPatronList + + DelPatronList( { patron_list_id => $list_id [, owner => $owner ] } ); + +=cut + +sub DelPatronList { + my ($params) = @_; + + $params->{owner} ||= C4::Context->userenv->{'number'}; + + unless ( $params->{patron_list_id} ) { + croak("No patron list id passed in!"); + } + unless ( $params->{owner} ) { + carp("No owner passed in or defined!"); + return; + } + + delete( $params->{owner} ) if ( C4::Context->IsSuperLibrarian() ); + + return Koha::Database->new()->schema()->resultset('PatronList') + ->search($params)->single()->delete(); +} + +=head2 AddPatronList + + AddPatronList( { name => $name [, owner => $owner ] } ); + +=cut + +sub AddPatronList { + my ($params) = @_; + + $params->{owner} ||= C4::Context->userenv->{'number'}; + + unless ( $params->{owner} ) { + carp("No owner passed in or defined!"); + return; + } + + unless ( $params->{name} ) { + carp("No list name passed in!"); + return; + } + + return Koha::Database->new()->schema()->resultset('PatronList') + ->create($params); +} + +=head2 ModPatronList + + ModPatronList( { patron_list_id => $id, name => $name [, owner => $owner ] } ); + +=cut + +sub ModPatronList { + my ($params) = @_; + + unless ( $params->{patron_list_id} ) { + carp("No patron list id passed in!"); + return; + } + + my ($list) = GetPatronLists( + { + patron_list_id => $params->{patron_list_id}, + owner => $params->{owner} + } + ); + + return $list->update($params); +} + +=head2 AddPatronsToList + + AddPatronsToList({ list => $list, cardnumbers => \@cardnumbers }); + +=cut + +sub AddPatronsToList { + my ($params) = @_; + + my $list = $params->{list}; + my $cardnumbers = $params->{'cardnumbers'}; + my $borrowernumbers = $params->{'borrowernumbers'}; + + return unless ( $list && ( $cardnumbers || $borrowernumbers ) ); + + my @borrowernumbers; + + if ($cardnumbers) { + @borrowernumbers = + Koha::Database->new()->schema()->resultset('Borrower')->search( + { cardnumber => { 'IN' => $cardnumbers } }, + { columns => [qw/ borrowernumber /] } + )->get_column('borrowernumber')->all(); + } + else { + @borrowernumbers = @$borrowernumbers; + } + + my $patron_list_id = $list->patron_list_id(); + + my $plp_rs = Koha::Database->new()->schema()->resultset('PatronListPatron'); + + my @results; + foreach my $borrowernumber (@borrowernumbers) { + my $result = $plp_rs->update_or_create( + { + patron_list_id => $patron_list_id, + borrowernumber => $borrowernumber + } + ); + push( @results, $result ); + } + + return wantarray() ? @results : \@results; +} + +=head2 DelPatronsFromList + + DelPatronsFromList({ list => $list, patron_list_patrons => \@patron_list_patron_ids }); + +=cut + +sub DelPatronsFromList { + my ($params) = @_; + + my $list = $params->{list}; + my $patron_list_patrons = $params->{patron_list_patrons}; + + return unless ( $list && $patron_list_patrons ); + + return Koha::Database->new()->schema()->resultset('PatronListPatron') + ->search( { patron_list_patron_id => { 'IN' => $patron_list_patrons } } ) + ->delete(); +} + +=head1 AUTHOR + +Kyle M Hall, Ekyle@bywatersolutions.comE + +=cut + +1; + +__END__ diff --git a/Koha/Schema/Result/PatronList.pm b/Koha/Schema/Result/PatronList.pm new file mode 100644 index 0000000..8d1d9dc --- /dev/null +++ b/Koha/Schema/Result/PatronList.pm @@ -0,0 +1,90 @@ +package Koha::Schema::Result::PatronList; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + + +=head1 NAME + +Koha::Schema::Result::PatronList + +=cut + +__PACKAGE__->table("patron_lists"); + +=head1 ACCESSORS + +=head2 patron_list_id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 name + + data_type: 'varchar' + is_nullable: 0 + size: 255 + +=head2 owner + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +=cut + +__PACKAGE__->add_columns( + "patron_list_id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "name", + { data_type => "varchar", is_nullable => 0, size => 255 }, + "owner", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, +); +__PACKAGE__->set_primary_key("patron_list_id"); + +=head1 RELATIONS + +=head2 patron_list_patrons + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "patron_list_patrons", + "Koha::Schema::Result::PatronListPatron", + { "foreign.patron_list_id" => "self.patron_list_id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + +=head2 owner + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "owner", + "Koha::Schema::Result::Borrower", + { borrowernumber => "owner" }, + { on_delete => "CASCADE", on_update => "CASCADE" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07000 @ 2013-07-10 10:39:50 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:XegvNUkfR/cYwxlLLX3h3A + + +# You can replace this text with custom content, and it will be preserved on regeneration +1; diff --git a/Koha/Schema/Result/PatronListPatron.pm b/Koha/Schema/Result/PatronListPatron.pm new file mode 100644 index 0000000..cb7ee6b --- /dev/null +++ b/Koha/Schema/Result/PatronListPatron.pm @@ -0,0 +1,90 @@ +package Koha::Schema::Result::PatronListPatron; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + + +=head1 NAME + +Koha::Schema::Result::PatronListPatron + +=cut + +__PACKAGE__->table("patron_list_patrons"); + +=head1 ACCESSORS + +=head2 patron_list_patron_id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 patron_list_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +=head2 borrowernumber + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +=cut + +__PACKAGE__->add_columns( + "patron_list_patron_id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "patron_list_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "borrowernumber", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, +); +__PACKAGE__->set_primary_key("patron_list_patron_id"); + +=head1 RELATIONS + +=head2 borrowernumber + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "borrowernumber", + "Koha::Schema::Result::Borrower", + { borrowernumber => "borrowernumber" }, + { on_delete => "CASCADE", on_update => "CASCADE" }, +); + +=head2 patron_list + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "patron_list", + "Koha::Schema::Result::PatronList", + { patron_list_id => "patron_list_id" }, + { on_delete => "CASCADE", on_update => "CASCADE" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07000 @ 2013-07-10 10:39:50 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:c+znpWBlv6I+yi1EuGUKrQ + + +# You can replace this text with custom content, and it will be preserved on regeneration +1; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 8f9b30c..1efbcad 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -3214,6 +3214,47 @@ CREATE TABLE IF NOT EXISTS plugin_data ( PRIMARY KEY (plugin_class,plugin_key) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table structure for table `patron_lists` +-- + +DROP TABLE IF EXISTS patron_lists; +CREATE TABLE patron_lists ( + patron_list_id int(11) NOT NULL AUTO_INCREMENT, -- unique identifier + name varchar(255) CHARACTER SET utf8 NOT NULL, -- the list's name + owner int(11) NOT NULL, -- borrowernumber of the list creator + PRIMARY KEY (patron_list_id), + KEY owner (owner) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Constraints for table `patron_lists` +-- +ALTER TABLE `patron_lists` + ADD CONSTRAINT patron_lists_ibfk_1 FOREIGN KEY (`owner`) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; + +-- +-- Table structure for table 'patron_list_patrons' +-- + +DROP TABLE IF EXISTS patron_list_patrons; +CREATE TABLE patron_list_patrons ( + patron_list_patron_id int(11) NOT NULL AUTO_INCREMENT, -- unique identifier + patron_list_id int(11) NOT NULL, -- the list this entry is part of + borrowernumber int(11) NOT NULL, -- the borrower that is part of this list + PRIMARY KEY (patron_list_patron_id), + KEY patron_list_id (patron_list_id), + KEY borrowernumber (borrowernumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Constraints for table `patron_list_patrons` +-- +ALTER TABLE `patron_list_patrons` + ADD CONSTRAINT patron_list_patrons_ibfk_1 FOREIGN KEY (patron_list_id) REFERENCES patron_lists (patron_list_id) ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT patron_list_patrons_ibfk_2 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; + + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 1f7b491..d91dc20 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -7044,6 +7044,45 @@ if ( CheckVersion($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.13.00.XXX"; +if ( CheckVersion($DBversion) ) { + + $dbh->do(q{ + CREATE TABLE IF NOT EXISTS `patron_lists` ( + patron_list_id int(11) NOT NULL AUTO_INCREMENT, + name varchar(255) CHARACTER SET utf8 NOT NULL, + owner int(11) NOT NULL, + PRIMARY KEY (patron_list_id), + KEY owner (owner) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + }); + + $dbh->do(q{ + ALTER TABLE `patron_lists` + ADD CONSTRAINT patron_lists_ibfk_1 FOREIGN KEY (`owner`) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; + }); + + $dbh->do(q{ + CREATE TABLE patron_list_patrons ( + patron_list_patron_id int(11) NOT NULL AUTO_INCREMENT, + patron_list_id int(11) NOT NULL, + borrowernumber int(11) NOT NULL, + PRIMARY KEY (patron_list_patron_id), + KEY patron_list_id (patron_list_id), + KEY borrowernumber (borrowernumber) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + }); + + $dbh->do(q{ + ALTER TABLE `patron_list_patrons` + ADD CONSTRAINT patron_list_patrons_ibfk_1 FOREIGN KEY (patron_list_id) REFERENCES patron_lists (patron_list_id) ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT patron_list_patrons_ibfk_2 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE; + }); + + print "Upgrade to $DBversion done (Bug 10565 - Add a 'Patron List' feature for storing and manipulating collections of patrons)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt index f44754a..cefbfd5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/member.tt @@ -1,6 +1,73 @@ [% INCLUDE 'doc-head-open.inc' %] Koha › Patrons [% IF ( searching ) %]› Search results[% END %] [% INCLUDE 'doc-head-close.inc' %] + + + [% INCLUDE 'header.inc' %] @@ -15,6 +82,12 @@
+ [% IF patron_list %] +
+ Added [% patrons_added_to_list.size %] patrons to [% patron_list.name %]. +
+ [% END %] + [% INCLUDE 'patron-toolbar.inc' %] [% IF ( no_add ) %]

Cannot add patron

@@ -36,13 +109,53 @@
[% END %] - [% IF ( resultsloop ) %] -

Results [% from %] to [% to %] of [% numresults %] found for [% IF ( member ) %]'[% member %]'[% END %][% IF ( surname ) %]'[% surname %]'[% END %]

+ [% IF ( resultsloop ) %] +
+
+

Results [% from %] to [% to %] of [% numresults %] found for [% IF ( member ) %]'[% member %]'[% END %][% IF ( surname ) %]'[% surname %]'[% END %]

+ +
+ Select all + | + Clear all + | + + + + + + + + + + [% FOREACH key IN search_parameters.keys %] + + [% END %] + + + +
+
+ @@ -65,6 +178,7 @@ [% END %] [% END %] +
  Card Name Cat
[% resultsloo.cardnumber %] @@ -92,11 +206,12 @@
[% IF ( multipage ) %][% paginationbar %][% END %]
- [% ELSE %] - [% IF ( searching ) %] -
No results found
- [% END %] - [% END %] +
+ [% ELSE %] + [% IF ( searching ) %] +
No results found
+ [% END %] + [% END %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/add-modify.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/add-modify.tt new file mode 100644 index 0000000..5ec0cd1 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/add-modify.tt @@ -0,0 +1,56 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Patron lists › New list +[% INCLUDE 'doc-head-close.inc' %] + + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
+
+

New patron list

+ +
+
+ + Create a new patron list + +
    +
  1. + + +
  2. + +
  3. + Owner: [% loggedinusername %] +
  4. +
+ +
+ + + + Cancel +
+
+
+[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/list.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/list.tt new file mode 100644 index 0000000..ebcd71f --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/list.tt @@ -0,0 +1,132 @@ +[% USE KohaDates %] +[% INCLUDE 'doc-head-open.inc' %] +Koha › Patron lists › New list +[% INCLUDE 'doc-head-close.inc' %] + + + +[% INCLUDE 'datatables-strings.inc' %] + + + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + +
+
+

[% list.name %]

+ +
+
+ Add patrons + + + +
+ +
+ Patrons to be added +
+
+ +
+ +

+ + Cancel +

+ + + + + + + + + + + + + + + + + + [% FOREACH p IN list.patron_list_patrons %] + + + + + + + + + + + + [% END %] + +
CardFirstnameSurnameAddressCategoryLibraryExpires onCirc notes
+ + [% p.borrowernumber.cardnumber %] + + [% p.borrowernumber.firstname %][% p.borrowernumber.surname %] + [% p.borrowernumber.address %] + [% p.borrowernumber.address2 %] + [% p.borrowernumber.city %] + [% p.borrowernumber.state %] + [% p.borrowernumber.country %] + [% p.borrowernumber.categorycode.description %] ([% p.borrowernumber.categorycode.categorycode %])[% p.borrowernumber.branchcode.branchname %][% p.borrowernumber.dateexpiry | $KohaDates %][% p.borrowernumber.borrowernotes %]
+ + + + Cancel +
+
+
+[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/lists.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/lists.tt new file mode 100644 index 0000000..972f36d --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/patron_lists/lists.tt @@ -0,0 +1,74 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Patron lists +[% INCLUDE 'doc-head-close.inc' %] + + + +[% INCLUDE 'datatables-strings.inc' %] + + + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + +
+
+

Your patron lists

+ + + + + + + + + + + + + + + + [% FOREACH l IN lists %] + + + + + + + + [% END %] + +
NamePatrons in list   
[% l.name %][% l.patron_list_patrons.size || 0 %] + + Add patrons + + + + Edit + + + + Delete + +
+
+
+[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt index 957d559..b4b899c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt @@ -128,11 +128,29 @@

Batch patron modification

- Use a file -
    -
  1. -
+ Use a file +
    +
  1. +
+ + [% IF patron_lists %] +
+ Or use a patron list +
    +
  1. + + +
  2. +
+
+ [% END %] +
Or list cardnumbers one by one
    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 4fff721..b72be1e 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 @@ -15,7 +15,10 @@

    Patrons and circulation

    - [% IF ( CAN_user_tools_moderate_comments ) %] +
    Patron lists +
    Manage lists of patrons.
    + +[% IF ( CAN_user_tools_moderate_comments ) %]
    Comments [% IF ( pendingcomments ) %][% pendingcomments %][% END %]
    Moderate patron comments.
    [% END %] diff --git a/members/member.pl b/members/member.pl index 47f7cb7..4396295 100755 --- a/members/member.pl +++ b/members/member.pl @@ -33,6 +33,7 @@ use C4::Branch; use C4::Category; use Koha::DateUtils; use File::Basename; +use Koha::List::Patron; my $input = new CGI; my $quicksearch = $input->param('quicksearch'); @@ -49,6 +50,15 @@ my ($template, $loggedinuser, $cookie) my $theme = $input->param('theme') || "default"; +my $add_to_patron_list = $input->param('add_to_patron_list'); +my $add_to_patron_list_which = $input->param('add_to_patron_list_which'); +my $new_patron_list = $input->param('new_patron_list'); +my @borrowernumbers = $input->param('borrowernumber'); +$input->delete( + 'add_to_patron_list', 'add_to_patron_list_which', + 'new_patron_list', 'borrowernumber', +); + my $patron = $input->Vars; foreach (keys %$patron){ delete $$patron{$_} unless($$patron{$_}); @@ -115,6 +125,29 @@ if ($member || keys %$patron) { ($results) = Search( $member || $patron, \@orderby, undef, undef, \@searchfields, $search_scope ); } +if ($add_to_patron_list) { + my $patron_list; + + if ( $add_to_patron_list eq 'new' ) { + $patron_list = AddPatronList( { name => $new_patron_list } ); + } + else { + $patron_list = + [ GetPatronLists( { patron_list_id => $add_to_patron_list } ) ]->[0]; + } + + if ( $add_to_patron_list_which eq 'all' ) { + @borrowernumbers = map { $_->{borrowernumber} } @$results; + } + + my @patrons_added_to_list = AddPatronsToList( { list => $patron_list, borrowernumbers => \@borrowernumbers } ); + + $template->param( + patron_list => $patron_list, + patrons_added_to_list => \@patrons_added_to_list, + ) +} + if ($results) { for my $field ('categorycode','branchcode'){ next unless ($patron->{$field}); @@ -170,24 +203,29 @@ my $base_url = my @letters = map { {letter => $_} } ( 'A' .. 'Z'); $template->param( - letters => \@letters, + %$patron, + letters => \@letters, paginationbar => pagination_bar( $base_url, - int( $count / $resultsperpage ) + ($count % $resultsperpage ? 1 : 0), - $startfrom, 'startfrom' + int( $count / $resultsperpage ) + ( $count % $resultsperpage ? 1 : 0 ), + $startfrom, + 'startfrom' ), - startfrom => $startfrom, - from => ($startfrom-1)*$resultsperpage+1, - to => $to, - multipage => ($count != $to || $startfrom!=1), - advsearch => ($$patron{categorycode} || $$patron{branchcode}), - branchloop=>\@branchloop, - categories=>\@categories, - searching => "1", - actionname =>basename($0), - %$patron, - numresults => $count, - resultsloop => \@resultsdata, - ); + startfrom => $startfrom, + from => ( $startfrom - 1 ) * $resultsperpage + 1, + to => $to, + multipage => ( $count != $to || $startfrom != 1 ), + advsearch => ( $$patron{categorycode} || $$patron{branchcode} ), + branchloop => \@branchloop, + categories => \@categories, + searching => "1", + actionname => basename($0), + numresults => $count, + resultsloop => \@resultsdata, + results_per_page => $resultsperpage, + member => $member, + search_parameters => \%parameters, + patron_lists => [ GetPatronLists() ], +); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/patron_lists/add-modify.pl b/patron_lists/add-modify.pl new file mode 100755 index 0000000..ed67932 --- /dev/null +++ b/patron_lists/add-modify.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl + +# Copyright 2013 ByWater Solutions +# +# 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::Output; +use Koha::List::Patron; + +my $cgi = new CGI; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "patron_lists/add-modify.tt", + query => $cgi, + type => "intranet", + authnotrequired => 1, + } +); + +my $id = $cgi->param('patron_list_id'); +my $name = $cgi->param('name'); + +if ($id) { + my ($list) = GetPatronLists( { patron_list_id => $id } ); + $template->param( list => $list ); +} + +if ($name) { + if ($id) { + ModPatronList( { patron_list_id => $id, name => $name } ); + print $cgi->redirect('lists.pl'); + } + else { + my $list = AddPatronList( { name => $name } ); + print $cgi->redirect( + "list.pl?patron_list_id=" . $list->patron_list_id() ); + } + + exit; +} + +output_html_with_http_headers( $cgi, $cookie, $template->output ); diff --git a/patron_lists/delete.pl b/patron_lists/delete.pl new file mode 100755 index 0000000..dfa698b --- /dev/null +++ b/patron_lists/delete.pl @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +# Copyright 2013 ByWater Solutions +# +# 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::Output; +use Koha::List::Patron; + +my $cgi = new CGI; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "patron_lists/lists.tt", + query => $cgi, + type => "intranet", + authnotrequired => 1, + } +); + +my $id = $cgi->param('patron_list_id'); + +DelPatronList( { patron_list_id => $id } ); + +print $cgi->redirect('lists.pl'); diff --git a/patron_lists/list.pl b/patron_lists/list.pl new file mode 100755 index 0000000..2723e71 --- /dev/null +++ b/patron_lists/list.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl + +# Copyright 2013 ByWater Solutions +# +# 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::Output; +use Koha::List::Patron; + +my $cgi = new CGI; + +my ( $template, $logged_in_user, $cookie ) = get_template_and_user( + { + template_name => "patron_lists/list.tt", + query => $cgi, + type => "intranet", + authnotrequired => 1, + } +); + +my ($list) = + GetPatronLists( { patron_list_id => $cgi->param('patron_list_id') } ); + +my @patrons_to_add = $cgi->param('patrons_to_add'); +if (@patrons_to_add) { + AddPatronsToList( { list => $list, cardnumbers => \@patrons_to_add } ); +} + +my @patrons_to_remove = $cgi->param('patrons_to_remove'); +if (@patrons_to_remove) { + DelPatronsFromList( { list => $list, patron_list_patrons => \@patrons_to_remove } ); +} + +$template->param( list => $list ); + +output_html_with_http_headers( $cgi, $cookie, $template->output ); diff --git a/patron_lists/lists.pl b/patron_lists/lists.pl new file mode 100755 index 0000000..0244511 --- /dev/null +++ b/patron_lists/lists.pl @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +# Copyright 2013 ByWater Solutions +# +# 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::Output; +use Koha::List::Patron; + +my $cgi = new CGI; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "patron_lists/lists.tt", + query => $cgi, + type => "intranet", + authnotrequired => 1, + } +); + +my @lists = GetPatronLists(); + +$template->param( lists => \@lists ); + +output_html_with_http_headers( $cgi, $cookie, $template->output ); diff --git a/patron_lists/patrons.pl b/patron_lists/patrons.pl new file mode 100755 index 0000000..510f7e0 --- /dev/null +++ b/patron_lists/patrons.pl @@ -0,0 +1,59 @@ +#!/usr/bin/perl + +# Copyright 2013 ByWater Solutions +# +# 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::Output; +use Koha::List::Patron; + +my $cgi = new CGI; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "patron_lists/add-modify.tt", + query => $cgi, + type => "intranet", + authnotrequired => 1, + } +); + +my $id = $cgi->param('patron_list_id'); +my $name = $cgi->param('name'); + +if ($id) { + my ($list) = GetPatronLists( { patron_list_id => $id } ); + $template->param( list => $list ); +} + +if ($name) { + if ($id) { + ModPatronList( { patron_list_id => $id, name => $name } ); + } + else { + AddPatronList( { name => $name } ); + } + + print $cgi->redirect('lists.pl'); + exit; +} + +output_html_with_http_headers( $cgi, $cookie, $template->output ); diff --git a/t/db_dependent/PatronLists.t b/t/db_dependent/PatronLists.t new file mode 100755 index 0000000..146b4f0 --- /dev/null +++ b/t/db_dependent/PatronLists.t @@ -0,0 +1,75 @@ +#!/usr/bin/perl +# +use Modern::Perl; + +use Test::More tests => 9; + +BEGIN { + use_ok('C4::Context'); + use_ok('Koha::List::Patron'); +} + +my $dbh = C4::Context->dbh; +my $sth = $dbh->prepare("SELECT * FROM borrowers ORDER BY RAND() LIMIT 10"); +$sth->execute(); +my @borrowers = @{ $sth->fetchall_arrayref( {} ) }; + +my @lists = GetPatronLists( { owner => 1 } ); +my $list_count_original = @lists; + +my $list1 = AddPatronList( { name => 'Test List 1', owner => 1 } ); +ok( $list1->name() eq 'Test List 1', 'AddPatronList works' ); + +my $list2 = AddPatronList( { name => 'Test List 2', owner => 1 } ); + +ModPatronList( + { + patron_list_id => $list2->patron_list_id(), + name => 'Test List 3', + owner => 1 + } +); +$list2->discard_changes(); +ok( $list2->name() eq 'Test List 3', 'ModPatronList works' ); + +AddPatronsToList( + { list => $list1, cardnumbers => [ map { $_->{cardnumber} } @borrowers ] } +); +ok( + scalar @borrowers == + $list1->patron_list_patrons()->search_related('borrowernumber')->all(), + 'AddPatronsToList works for cardnumbers' +); + +AddPatronsToList( + { + list => $list2, + borrowernumbers => [ map { $_->{borrowernumber} } @borrowers ] + } +); +ok( + scalar @borrowers == + $list2->patron_list_patrons()->search_related('borrowernumber')->all(), + 'AddPatronsToList works for borrowernumbers' +); + +my @ids = + $list1->patron_list_patrons()->get_column('patron_list_patron_id')->all(); +DelPatronsFromList( + { + list => $list1, + patron_list_patrons => \@ids, + } +); +$list1->discard_changes(); +ok( !$list1->patron_list_patrons()->count(), 'DelPatronsFromList works.' ); + +@lists = GetPatronLists( { owner => 1 } ); +ok( @lists == $list_count_original + 2, 'GetPatronLists works' ); + +DelPatronList( { patron_list_id => $list1->patron_list_id(), owner => 1 } ); +DelPatronList( { patron_list_id => $list2->patron_list_id(), owner => 1 } ); + +@lists = + GetPatronLists( { patron_list_id => $list1->patron_list_id(), owner => 1 } ); +ok( !@lists, 'DelPatronList works' ); diff --git a/tools/modborrowers.pl b/tools/modborrowers.pl index 1bba4a0..7009014 100755 --- a/tools/modborrowers.pl +++ b/tools/modborrowers.pl @@ -34,6 +34,7 @@ use C4::Members::Attributes; use C4::Members::AttributeTypes qw/GetAttributeTypes_hashref/; use C4::Output; use List::MoreUtils qw /any uniq/; +use Koha::List::Patron; my $input = new CGI; my $op = $input->param('op') || 'show_form'; @@ -50,12 +51,11 @@ 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 $filefh = $input->upload('uploadfile'); + my $filecontent = $input->param('filecontent'); + my $patron_list_id = $input->param('patron_list_id'); my @borrowers; my @cardnumbers; my @notfoundcardnumbers; @@ -67,6 +67,13 @@ if ( $op eq 'show' ) { $content =~ s/[\r\n]*$//g; push @cardnumbers, $content if $content; } + } elsif ( $patron_list_id ) { + my ($list) = GetPatronLists( { patron_list_id => $patron_list_id } ); + + @cardnumbers = + $list->patron_list_patrons()->search_related('borrowernumber') + ->get_column('cardnumber')->all(); + } else { if ( my $list = $input->param('cardnumberlist') ) { push @cardnumbers, split( /\s\n/, $list ); @@ -314,6 +321,9 @@ if ( $op eq 'do' ) { $template->param( borrowers => \@borrowers ); $template->param( errors => \@errors ); +} else { + + $template->param( patron_lists => [ GetPatronLists() ] ); } $template->param( -- 1.7.2.5