From 4888bc6bd7260dd9395506c4d8376d750f69114f 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: 1) Apply this patch 2) Run updatedatabase.pl 3) Access the patron lists feature from the "More" pulldown on the main 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) Go back to the Patron Lists feature and delete your lists. --- Koha/List/Patron.pm | 218 ++++++++++++++++++++ Koha/Schema/Result/PatronList.pm | 90 ++++++++ Koha/Schema/Result/PatronListPatron.pm | 90 ++++++++ installer/data/mysql/kohastructure.sql | 41 ++++ installer/data/mysql/updatedatabase.pl | 39 ++++ .../intranet-tmpl/prog/en/includes/header.inc | 1 + .../prog/en/modules/members/member.tt | 129 +++++++++++- .../prog/en/modules/patron_lists/add-modify.tt | 56 +++++ .../prog/en/modules/patron_lists/lists.tt | 74 +++++++ .../prog/en/modules/tools/modborrowers.tt | 26 ++- members/member.pl | 70 +++++-- patron_lists/add-modify.pl | 59 ++++++ patron_lists/delete.pl | 43 ++++ patron_lists/list.pl | 54 +++++ patron_lists/lists.pl | 43 ++++ tools/modborrowers.pl | 18 ++- 16 files changed, 1020 insertions(+), 31 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/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 diff --git a/Koha/List/Patron.pm b/Koha/List/Patron.pm new file mode 100644 index 0000000..5cd91c9 --- /dev/null +++ b/Koha/List/Patron.pm @@ -0,0 +1,218 @@ +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} } ); + + 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 f5e1862..21bb80c 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 adc1e7f..e0ca020 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -7036,6 +7036,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/includes/header.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/header.inc index 58f721f..3340b0a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/header.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/header.inc @@ -12,6 +12,7 @@ More