From 0ca60a2c4cbaf671e52e8d189aeb53833d7dde37 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Mon, 2 May 2016 15:00:39 +0000 Subject: [PATCH] Bug 14570 - Make it possible to add multiple guarantors to a record This patch adds the ability to set an unlimited number of guarantors for a given patron. As before, each guarantor may be linked to another Koha patron, and all the behavior that applies to a given guarantor remains the same. Test Plan: 1) Apply this patch 2) Run updatedatabase.pl 3) Find some patrons with guarantors, verify the still have their guarantor 4) Test adding and removing guarantors on a patron record, both Koha users and not 5) Verify the "Add child" button works 6) Verify NoIssuesChargeGuarantees still works 7) Verify tools/cleanborrowers.pl will not delete a guarantor 8) Verify the guarantors are displayed on moremember.pl 9) Verify the guarantor is removed by members/update-child.pl 10) Verify the guarantor is removed by misc/cronjobs/j2a.pl 11) Verify import patrons converts guarantor_id, relationship, contactfirstname, and contactsurname into a guarantor 12) prove t/Patron.t 13) prove t/db_dependent/Circulation.t 14) prove t/db_dependent/Circulation/NoIssuesChargeGuarantees.t 15) prove t/db_dependent/Items.t 16) prove t/db_dependent/Koha/Patrons.t 17) prove t/db_dependent/Members.t 18) prove t/db_dependent/Patron/Relationships.t --- C4/Circulation.pm | 2 +- C4/Members.pm | 14 +- Koha/Item.pm | 11 + Koha/Object.pm | 8 +- Koha/Patron.pm | 88 ++++--- Koha/Patron/Relationship.pm | 73 ++++++ Koha/Patron/Relationships.pm | 94 +++++++ Koha/Schema/Result/Relationship.pm | 132 ++++++++++ circ/circulation.pl | 11 +- installer/data/mysql/atomicupdate/bug_14560.sql | 18 ++ installer/data/mysql/kohastructure.sql | 33 +-- koha-tmpl/intranet-tmpl/prog/en/columns.def | 1 - .../prog/en/includes/members-toolbar.inc | 11 +- .../prog/en/modules/circ/circulation.tt | 2 +- .../prog/en/modules/members/memberentrygen.tt | 283 +++++++++++++-------- .../prog/en/modules/members/moremember-brief.tt | 27 +- .../prog/en/modules/members/moremember.tt | 30 +-- koha-tmpl/intranet-tmpl/prog/js/members.js | 105 ++++---- .../bootstrap/en/modules/opac-memberentry.tt | 9 +- .../opac-tmpl/bootstrap/en/modules/opac-privacy.tt | 9 +- .../opac-tmpl/bootstrap/en/modules/opac-user.tt | 10 +- members/deletemem.pl | 14 +- members/memberentry.pl | 144 ++++++----- members/moremember.pl | 31 +-- members/update-child.pl | 37 +-- misc/cronjobs/j2a.pl | 57 ++++- opac/opac-memberentry.pl | 4 +- opac/opac-user.pl | 17 +- t/Patron.t | 24 +- t/db_dependent/Circulation.t | 9 +- .../Circulation/NoIssuesChargeGuarantees.t | 12 +- t/db_dependent/Items.t | 6 +- t/db_dependent/Koha/Patrons.t | 36 +-- t/db_dependent/Members.t | 18 +- t/db_dependent/Patron/Relationships.t | 181 +++++++++++++ tools/import_borrowers.pl | 26 ++ 36 files changed, 1154 insertions(+), 433 deletions(-) create mode 100644 Koha/Patron/Relationship.pm create mode 100644 Koha/Patron/Relationships.pm create mode 100644 Koha/Schema/Result/Relationship.pm create mode 100644 installer/data/mysql/atomicupdate/bug_14560.sql create mode 100755 t/db_dependent/Patron/Relationships.t diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 80ae062..7c6a82a 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -767,7 +767,7 @@ sub CanBookBeIssued { $no_issues_charge_guarantees = undef unless looks_like_number( $no_issues_charge_guarantees ); if ( defined $no_issues_charge_guarantees ) { my $p = Koha::Patrons->find( $borrower->{borrowernumber} ); - my @guarantees = $p->guarantees(); + my @guarantees = map { $_->guarantee } $p->guarantee_relationships(); my $guarantees_non_issues_charges; foreach my $g ( @guarantees ) { my ( $b, $n, $o ) = C4::Members::GetMemberAccountBalance( $g->id ); diff --git a/C4/Members.pm b/C4/Members.pm index dfe4cbd..5b7e4fa 100644 --- a/C4/Members.pm +++ b/C4/Members.pm @@ -209,7 +209,7 @@ sub patronflags { $no_issues_charge_guarantees = undef unless looks_like_number( $no_issues_charge_guarantees ); if ( defined $no_issues_charge_guarantees ) { my $p = Koha::Patrons->find( $patroninformation->{borrowernumber} ); - my @guarantees = $p->guarantees(); + my @guarantees = map { $_->guarantee } $p->guarantee_relationships; my $guarantees_non_issues_charges; foreach my $g ( @guarantees ) { my ( $b, $n, $o ) = C4::Members::GetMemberAccountBalance( $g->id ); @@ -1095,18 +1095,18 @@ sub GetBorrowersToExpunge { FROM borrowers JOIN categories USING (categorycode) LEFT JOIN ( - SELECT guarantorid - FROM borrowers - WHERE guarantorid IS NOT NULL - AND guarantorid <> 0 - ) as tmp ON borrowers.borrowernumber=tmp.guarantorid + SELECT guarantor_id + FROM relationships + WHERE guarantor_id IS NOT NULL + AND guarantor_id <> 0 + ) as tmp ON borrowers.borrowernumber=tmp.guarantor_id LEFT JOIN old_issues USING (borrowernumber) LEFT JOIN issues USING (borrowernumber)|; if ( $filterpatronlist ){ $query .= q| LEFT JOIN patron_list_patrons USING (borrowernumber)|; } $query .= q| WHERE category_type <> 'S' - AND tmp.guarantorid IS NULL + AND tmp.guarantor_id IS NULL |; my @query_params; if ( $filterbranch && $filterbranch ne "" ) { diff --git a/Koha/Item.pm b/Koha/Item.pm index 52a7700..4b21d50 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -26,6 +26,7 @@ use Koha::Database; use C4::Context; use Koha::IssuingRules; use Koha::Item::Transfer; +use Koha::Biblios; use Koha::Patrons; use Koha::Libraries; @@ -170,6 +171,16 @@ sub article_request_type { return $issuing_rule->article_requests || q{} } +=head3 biblio + +=cut + +sub biblio { + my ( $self ) = @_; + + return Koha::Biblios->find( $self->biblionumber ); +} + =head3 type =cut diff --git a/Koha/Object.pm b/Koha/Object.pm index 709d7f2..6fbceed 100644 --- a/Koha/Object.pm +++ b/Koha/Object.pm @@ -68,8 +68,12 @@ sub new { next if not exists $attributes->{$column_name} or defined $attributes->{$column_name}; delete $attributes->{$column_name}; } - $self->{_result} = $schema->resultset( $class->_type() ) - ->new($attributes); + + eval { + $self->{_result} = + $schema->resultset( $class->_type() )->new($attributes); + }; + Carp::cluck("ERROR: $@") if $@; } croak("No _type found! Koha::Object must be subclassed!") diff --git a/Koha/Patron.pm b/Koha/Patron.pm index 698134a..d3ba23b 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -25,15 +25,16 @@ use Carp; use C4::Context; use C4::Log; use Koha::Checkouts; +use Koha::Old::Checkouts; use Koha::Database; use Koha::DateUtils; use Koha::Holds; -use Koha::Old::Checkouts; +use Koha::Patrons; use Koha::Patron::Categories; +use Koha::Patron::Relationships; use Koha::Patron::HouseboundProfile; use Koha::Patron::HouseboundRole; use Koha::Patron::Images; -use Koha::Patrons; use Koha::Virtualshelves; use base qw(Koha::Object); @@ -107,41 +108,69 @@ sub category { return Koha::Patron::Category->_new_from_dbic( $self->_result->categorycode ); } -=head3 guarantor - -Returns a Koha::Patron object for this patron's guarantor +=head3 image =cut -sub guarantor { +sub image { my ( $self ) = @_; - return unless $self->guarantorid(); - - return Koha::Patrons->find( $self->guarantorid() ); + return Koha::Patron::Images->find( $self->borrowernumber ) } -sub image { +=head3 checkouts + +=cut + +sub checkouts { my ( $self ) = @_; - return Koha::Patron::Images->find( $self->borrowernumber ); + return Koha::Checkouts->search( { borrowernumber => $self->id } ); } +=head3 library + +=cut + sub library { my ( $self ) = @_; return Koha::Library->_new_from_dbic($self->_result->branchcode); } -=head3 guarantees +=head3 guarantor_relationships + +Returns Koha::Patron::Relationships object for this patron's guarantors -Returns the guarantees (list of Koha::Patron) of this patron +Returns the set of relationships for the patrons that are guarantors for this patron. + +This is returned instead of a Koha::Patron object because the guarantor +may not exist as a patron in Koha. If this is true, the guarantors name +exists in the Koha::Patron::Relationship object and will have no guarantor_id. =cut -sub guarantees { - my ( $self ) = @_; +sub guarantor_relationships { + my ($self) = @_; - return Koha::Patrons->search( { guarantorid => $self->borrowernumber } ); + return Koha::Patron::Relationships->search( { guarantee_id => $self->id } ); +} + +=head3 guarantee_relationships + +Returns Koha::Patron::Relationships object for this patron's guarantors + +Returns the set of relationships for the patrons that are guarantees for this patron. + +The method returns Koha::Patron::Relationship objects for the sake +of consistency with the guantors method. +A guarantee by definition must exist as a patron in Koha. + +=cut + +sub guarantee_relationships { + my ($self) = @_; + + return Koha::Patron::Relationships->search( { guarantor_id => $self->id } ); } =head3 housebound_profile @@ -179,23 +208,22 @@ Returns the siblings of this patron. =cut sub siblings { - my ( $self ) = @_; + my ($self) = @_; - my $guarantor = $self->guarantor; + my @guarantors = $self->guarantor_relationships()->guarantors(); - return unless $guarantor; + return unless @guarantors; - return Koha::Patrons->search( - { - guarantorid => { - '!=' => undef, - '=' => $guarantor->id, - }, - borrowernumber => { - '!=' => $self->borrowernumber, - } - } - ); + my @siblings = + map { $_->guarantee_relationships()->guarantees() } @guarantors; + + return unless @siblings; + + my %seen; + @siblings = + grep { !$seen{ $_->id }++ && ( $_->id != $self->id ) } @siblings; + + return wantarray ? @siblings : Koha::Patrons->search( { borrowernumber => { -in => [ map { $_->id } @siblings ] } } ); } =head3 wants_check_for_previous_checkout diff --git a/Koha/Patron/Relationship.pm b/Koha/Patron/Relationship.pm new file mode 100644 index 0000000..424acbf --- /dev/null +++ b/Koha/Patron/Relationship.pm @@ -0,0 +1,73 @@ +package Koha::Patron::Relationship; + +# 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 3 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 Carp; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Patron::Relationship - A class to represent relationships between patrons + +Patrons in Koha may be guarantors or guarantees. This class models that relationship +and provides a way to access those relationships. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 guarantor + +Returns the Koha::Patron object for the guarantor, if there is one + +=cut + +sub guarantor { + my ( $self ) = @_; + + return unless $self->guarantor_id; + + return Koha::Patrons->find( $self->guarantor_id ); +} + +=head3 guarantee + +Returns the Koha::Patron object for the guarantee + +=cut + +sub guarantee { + my ( $self ) = @_; + + return Koha::Patrons->find( $self->guarantee_id ); +} + +=head3 type + +=cut + +sub _type { + return 'Relationship'; +} + +1; diff --git a/Koha/Patron/Relationships.pm b/Koha/Patron/Relationships.pm new file mode 100644 index 0000000..e9da572 --- /dev/null +++ b/Koha/Patron/Relationships.pm @@ -0,0 +1,94 @@ +package Koha::Patron::Relationships; + +# 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 3 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 Carp; +use List::MoreUtils qw( uniq ); + +use Koha::Database; +use Koha::Patrons; +use Koha::Patron::Relationship; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Patron::Relationships - Koha Patron Relationship Object set class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 guarantors + +Returns all the guarantors in this set of relationships as a list of Koha::Patron objects +or as a Koha::Patrons object depending on the calling context + +=cut + +sub guarantors { + my ($self) = @_; + + my $rs = $self->_resultset(); + + my @guarantor_ids = $rs->get_column('guarantor_id')->all(); + # Guarantors may not have a guarantor_id, strip out undefs + @guarantor_ids = grep { defined $_ } @guarantor_ids; + @guarantor_ids = uniq( @guarantor_ids ); + + my $guarantors = Koha::Patrons->search( { borrowernumber => \@guarantor_ids } ); + + return wantarray ? $guarantors->as_list : $guarantors; +} + +=head3 guarantees + +Returns all the guarantees in this set of relationships as a list of Koha::Patron objects +or as a Koha::Patrons object depending on the calling context + +=cut + +sub guarantees { + my ($self) = @_; + + my $rs = $self->_resultset(); + + my @guarantee_ids = uniq( $rs->get_column('guarantee_id')->all() ); + + my $guarantees = Koha::Patrons->search( { borrowernumber => \@guarantee_ids } ); + + return wantarray ? $guarantees->as_list : $guarantees; +} + +=cut + +=head3 type + +=cut + +sub _type { + return 'Relationship'; +} + +sub object_class { + return 'Koha::Patron::Relationship'; +} + +1; diff --git a/Koha/Schema/Result/Relationship.pm b/Koha/Schema/Result/Relationship.pm new file mode 100644 index 0000000..c815df4 --- /dev/null +++ b/Koha/Schema/Result/Relationship.pm @@ -0,0 +1,132 @@ +use utf8; +package Koha::Schema::Result::Relationship; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::Relationship + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("relationships"); + +=head1 ACCESSORS + +=head2 id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 guarantor_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 1 + +=head2 guarantee_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +=head2 relationship + + data_type: 'varchar' + is_nullable: 0 + size: 100 + +=head2 surname + + data_type: 'mediumtext' + is_nullable: 1 + +=head2 firstname + + data_type: 'mediumtext' + is_nullable: 1 + +=cut + +__PACKAGE__->add_columns( + "id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "guarantor_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, + "guarantee_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "relationship", + { data_type => "varchar", is_nullable => 0, size => 100 }, + "surname", + { data_type => "mediumtext", is_nullable => 1 }, + "firstname", + { data_type => "mediumtext", is_nullable => 1 }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("id"); + +=head1 RELATIONS + +=head2 guarantee + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "guarantee", + "Koha::Schema::Result::Borrower", + { borrowernumber => "guarantee_id" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); + +=head2 guarantor + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "guarantor", + "Koha::Schema::Result::Borrower", + { borrowernumber => "guarantor_id" }, + { + is_deferrable => 1, + join_type => "LEFT", + on_delete => "CASCADE", + on_update => "CASCADE", + }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2016-05-03 13:19:34 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2Nv437KMrKHvpQleXLOjYw + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/circ/circulation.pl b/circ/circulation.pl index b065267..69ef4bf 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -585,12 +585,12 @@ my $view = $batch my @relatives; if ( $borrowernumber ) { - if ( $patron ) { - if ( my $guarantor = $patron->guarantor ) { - push @relatives, $guarantor->borrowernumber; - push @relatives, $_->borrowernumber for $patron->siblings; + if ( my $patron = Koha::Patrons->find( $borrower->{borrowernumber} ) ) { + if ( my @guarantors = $patron->guarantor_relationships()->guarantors() ) { + push( @relatives, $_->id ) for @guarantors; + push( @relatives, $_->id ) for $patron->siblings(); } else { - push @relatives, $_->borrowernumber for $patron->guarantees; + push( @relatives, $_->id ) for $patron->guarantee_relationships()->guarantees(); } } } @@ -639,7 +639,6 @@ $template->param( AudioAlerts => C4::Context->preference("AudioAlerts"), fast_cataloging => $fast_cataloging, CircAutoPrintQuickSlip => C4::Context->preference("CircAutoPrintQuickSlip"), - activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), SuspendHoldsIntranet => C4::Context->preference('SuspendHoldsIntranet'), AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds'), RoutingSerials => C4::Context->preference('RoutingSerials'), diff --git a/installer/data/mysql/atomicupdate/bug_14560.sql b/installer/data/mysql/atomicupdate/bug_14560.sql new file mode 100644 index 0000000..9ba0743 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_14560.sql @@ -0,0 +1,18 @@ +DROP TABLE IF EXISTS relationships; +CREATE TABLE `relationships` ( + id INT(11) NOT NULL AUTO_INCREMENT, + guarantor_id INT(11) NULL DEFAULT NULL, + guarantee_id INT(11) NOT NULL, + relationship VARCHAR(100) COLLATE utf8_unicode_ci NOT NULL, + surname MEDIUMTEXT COLLATE utf8_unicode_ci NULL DEFAULT NULL, + firstname MEDIUMTEXT COLLATE utf8_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (id), + CONSTRAINT r_guarantor FOREIGN KEY ( guarantor_id ) REFERENCES borrowers ( borrowernumber ) ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT r_guarantee FOREIGN KEY ( guarantee_id ) REFERENCES borrowers ( borrowernumber ) ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +UPDATE borrowers LEFT JOIN borrowers guarantor ON ( borrowers.guarantorid = guarantor.borrowernumber ) SET borrowers.guarantorid = NULL WHERE guarantor.borrowernumber IS NULL; + +INSERT INTO relationships ( guarantor_id, guarantee_id, relationship, surname, firstname ) SELECT guarantorid, borrowernumber, relationship, contactname, contactfirstname FROM borrowers WHERE guarantorid IS NOT NULL OR contactname != ""; + +ALTER TABLE borrowers DROP guarantorid, DROP relationship, DROP contactname, DROP contactfirstname, DROP contacttitle; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index f40692e..ba3e35c 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -602,12 +602,7 @@ CREATE TABLE `deletedborrowers` ( -- stores data related to the patrons/borrower `lost` tinyint(1) default NULL, -- set to 1 for yes and 0 for no, flag to note that library marked this patron/borrower as having lost their card `debarred` date default NULL, -- until this date the patron can only check-in (no loans, no holds, etc.), is a fine based on days instead of money (YYY-MM-DD) `debarredcomment` VARCHAR(255) DEFAULT NULL, -- comment on the stop of patron - `contactname` mediumtext, -- used for children and profesionals to include surname or last name of guarentor or organization name - `contactfirstname` text, -- used for children to include first name of guarentor - `contacttitle` text, -- used for children to include title (Mr., Mrs., etc) of guarentor - `guarantorid` int(11) default NULL, -- borrowernumber used for children or professionals to link them to guarentors or organizations `borrowernotes` mediumtext, -- a note on the patron/borrower's account that is only visible in the staff client - `relationship` varchar(100) default NULL, -- used for children to include the relationship to their guarentor `sex` varchar(1) default NULL, -- patron/borrower's gender `password` varchar(60) default NULL, -- patron/borrower's encrypted password `flags` int(11) default NULL, -- will include a number associated with the staff member's permissions @@ -1625,12 +1620,7 @@ CREATE TABLE `borrowers` ( -- this table includes information about your patrons `lost` tinyint(1) default NULL, -- set to 1 for yes and 0 for no, flag to note that library marked this patron/borrower as having lost their card `debarred` date default NULL, -- until this date the patron can only check-in (no loans, no holds, etc.), is a fine based on days instead of money (YYY-MM-DD) `debarredcomment` VARCHAR(255) DEFAULT NULL, -- comment on the stop of the patron - `contactname` mediumtext, -- used for children and profesionals to include surname or last name of guarentor or organization name - `contactfirstname` text, -- used for children to include first name of guarentor - `contacttitle` text, -- used for children to include title (Mr., Mrs., etc) of guarentor - `guarantorid` int(11) default NULL, -- borrowernumber used for children or professionals to link them to guarentors or organizations `borrowernotes` mediumtext, -- a note on the patron/borrower's account that is only visible in the staff client - `relationship` varchar(100) default NULL, -- used for children to include the relationship to their guarentor `sex` varchar(1) default NULL, -- patron/borrower's gender `password` varchar(60) default NULL, -- patron/borrower's encrypted password `flags` int(11) default NULL, -- will include a number associated with the staff member's permissions @@ -1660,7 +1650,6 @@ CREATE TABLE `borrowers` ( -- this table includes information about your patrons KEY `categorycode` (`categorycode`), KEY `branchcode` (`branchcode`), UNIQUE KEY `userid` (`userid`), - KEY `guarantorid` (`guarantorid`), KEY `surname_idx` (`surname`(255)), KEY `firstname_idx` (`firstname`(255)), KEY `othernames_idx` (`othernames`(255)), @@ -3399,12 +3388,7 @@ CREATE TABLE IF NOT EXISTS `borrower_modifications` ( `lost` tinyint(1) DEFAULT NULL, `debarred` date DEFAULT NULL, `debarredcomment` varchar(255) DEFAULT NULL, - `contactname` mediumtext, - `contactfirstname` text, - `contacttitle` text, - `guarantorid` int(11) DEFAULT NULL, `borrowernotes` mediumtext, - `relationship` varchar(100) DEFAULT NULL, `sex` varchar(1) DEFAULT NULL, `password` varchar(30) DEFAULT NULL, `flags` int(11) DEFAULT NULL, @@ -3922,6 +3906,23 @@ CREATE TABLE `article_requests` ( CONSTRAINT `article_requests_ibfk_4` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE SET NULL ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +-- +-- Table structure for table 'guarantors_guarantees' +-- + +DROP TABLE IF EXISTS relationships; +CREATE TABLE `relationships` ( + id INT(11) NOT NULL AUTO_INCREMENT, + guarantor_id INT(11) NULL DEFAULT NULL, + guarantee_id INT(11) NOT NULL, + relationship VARCHAR(100) COLLATE utf8_unicode_ci NOT NULL, + surname MEDIUMTEXT COLLATE utf8_unicode_ci NULL DEFAULT NULL, + firstname MEDIUMTEXT COLLATE utf8_unicode_ci NULL DEFAULT NULL, + PRIMARY KEY (id), + CONSTRAINT r_guarantor FOREIGN KEY ( guarantor_id ) REFERENCES borrowers ( borrowernumber ) ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT r_guarantee FOREIGN KEY ( guarantee_id ) REFERENCES borrowers ( borrowernumber ) ON UPDATE CASCADE ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + /*!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/koha-tmpl/intranet-tmpl/prog/en/columns.def b/koha-tmpl/intranet-tmpl/prog/en/columns.def index c80975a..c82e31e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/columns.def +++ b/koha-tmpl/intranet-tmpl/prog/en/columns.def @@ -7,7 +7,6 @@ Other name Gender Relationship -Guarantor borrower number Street number Street type Address diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc index 503d6e6..938f807 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc @@ -133,17 +133,14 @@ function searchToHold(){
[% IF ( CAN_user_borrowers ) %] - [% IF ( guarantor ) %] - - [% ELSE %] - [% END %] - Edit + Edit + [% END %] [% IF ( CAN_user_borrowers ) %] - [% IF ( adultborrower AND activeBorrowerRelationship ) %] - Add child + [% IF ( adultborrower AND Koha.Preference('borrowerRelationship') ) %] + Add child [% END %] [% IF ( CAN_user_borrowers ) %] Change password diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt index 1444f2d..2d86712 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -888,7 +888,7 @@ No patron matched [% message | html %] [% IF relatives_issues_count %] -
  • Relatives' checkouts
  • +
  • [% relatives_issues_count %] Relatives' checkouts
  • [% END %]
  • diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt index a66826d..ea7c63a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt @@ -1,3 +1,4 @@ +[% USE To %] [% USE Koha %] [% USE KohaDates %] [% USE Branches %] @@ -25,14 +26,22 @@ $(document).ready(function() { $('#toolbar').fixFloat({ 'originalOffset': original_offset - additional_height }); }) - [% IF categorycode %] - update_category_code( "[% categorycode %]" ); - [% ELSE %] - if ( $("#categorycode_entry").length > 0 ){ - var category_code = $("#categorycode_entry").find("option:selected").val(); - update_category_code( category_code ); - } - [% END %] + [% IF categorycode %] + update_category_code( "[% categorycode %]" ); + [% ELSE %] + if ( $("#categorycode_entry").length > 0 ) { + var category_code = $("#categorycode_entry").find("option:selected").val(); + update_category_code( category_code ); + } + [% END %] + + [% IF guarantor %] + select_user( '[% guarantor.borrowernumber %]', [% To.json( guarantor.unblessed ) %] ); + $('#guarantor_add').ready(function() { + $('#guarantor_add').click(); + }); + [% END %] + }); $(document).ready(function() { @@ -383,106 +392,172 @@ $(document).ready(function() { [% END # hide fieldset %] -[% IF ( showguarantor ) %] - - [% UNLESS step_6 %] - - [% END %] -
    - Guarantor information -
      -[% IF ( P ) %] - [% IF ( guarantorid ) %] -
    1. - [% ELSE %] -
    2. -
    3. - - [% IF ( guarantorid ) %] - [% contactname %] - - [% ELSE %] - - [% END %] -
    4. -[% ELSE %] - [% IF ( C ) %] - [% IF ( guarantorid ) %] -
    5. - [% ELSE %] -
    6. - [% UNLESS nocontactname %] -
    7. - - [% IF ( guarantorid ) %] - [% contactname %] - - [% ELSE %] - - [% END %] -
    8. - [% END %] - [% UNLESS nocontactfirstname %] -
    9. - - [% IF ( guarantorid ) %] - [% contactfirstname %] - - [% ELSE %] - - [% END %] -
    10. - [% END %] - [% IF ( relshiploop ) %] -
    11. - - -
    12. - [% END %] - [% END %] -[% END %] -
    13. -   - [% IF ( guarantorid ) %] - - [% ELSE %] - - [% END %] - -
    14. - [% IF guarantorid && Koha.Preference('AllowStaffToSetCheckoutsVisibilityForGuarantor') %] -
    15. - - +
    16. + [% END %] + [% END %] +
    +
    + [% END # END relationships foreach %] + + +
    +
      +
    1. + Patron #: + + +
    2. + +
    3. + + + +
    4. + +
    5. + + + +
    6. + +
    7. + + +
    8. + +
    9. + + Cancel +
    10. +
    +
    + +
    + Add new guarantor +
      + + + [% IF catetory_type == 'P' %] +
    1. + + +
    2. [% ELSE %] - - +
    3. + + +
    4. + +
    5. + + +
    6. + + [% IF ( possible_relationships ) %] +
    7. + + +
    8. + [% END %] [% END %] - -
      Allow guarantor of this patron to view this patron's checkouts from the OPAC
      - - [% END %] -
    -
    +
  • +   + Add guarantor + Set to patron + Clear +
  • + + [% IF relationships && Koha.Preference('AllowStaffToSetCheckoutsVisibilityForGuarantor') %] +
  • + + +
    Allow guarantors of this patron to view this patron's checkouts from the OPAC
    +
  • + [% END %] + + + [% END %] + + [% UNLESS noaddress && noaddress2 && nocity && nostate && nozipcode && nocountry %] [% IF Koha.Preference( 'AddressFormat' ) %] [% INCLUDE "member-main-address-style-${ Koha.Preference( 'AddressFormat' ) }.inc" %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember-brief.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember-brief.tt index b95a4c0..df1a2bd 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember-brief.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember-brief.tt @@ -47,13 +47,26 @@
  • Initials: [% initials %]
  • Date of birth:[% dateofbirth | $KohaDates %]
  • Gender:[% IF ( sex == 'F' ) %]Female[% ELSIF ( sex == 'M' ) %]Male[% ELSE %][% sex %][% END %]
  • [% END %] - [% IF ( isguarantee ) %] - [% IF ( guaranteeloop ) %] -
  • Guarantees:
  • - [% END %] - [% ELSE %] - [% IF ( guarantor.borrowernumber ) %] -
  • Guarantor:[% guarantor.surname %], [% guarantor.firstname %]
  • + [% IF guarantees %] +
  • + Guarantees: + +
  • + [% ELSIF guarantor_relationships %] + [% FOREACH gr IN guarantor_relationships %] +
  • + Guarantor: + [% IF gr.guarantor_id %] + [% SET guarantor = gr.guarantor %] + [% guarantor.firstname %] [% guarantor.surname %] + [% ELSE %] + [% gr.firstname %] [% gr.surname %] + [% END %] +
  • [% END %] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt index 209671e..ca885f8 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt @@ -255,25 +255,21 @@ function validate1(date) { [% END %] - [% ELSIF guarantor %] -
  • - Guarantor: - [% IF guarantor.borrowernumber %] - [% guarantor.firstname | html %] [% guarantor.surname | html %] - [% ELSE %] - [% guarantor.firstname | html %] [% guarantor.surname | html %] - [% END %] -
  • + [% ELSIF guarantor_relationships %] + [% FOREACH gr IN guarantor_relationships %] +
  • + Guarantor: + [% IF gr.guarantor_id %] + [% SET guarantor = gr.guarantor %] + [% guarantor.firstname %] [% guarantor.surname %] + [% ELSE %] + [% gr.firstname %] [% gr.surname %] + [% END %] +
  • + [% END %] [% END %]
    -
    - [% IF ( guarantor.borrowernumber ) %] - Edit - [% ELSE %] - Edit - [% END %]
    - @@ -499,7 +495,7 @@ function validate1(date) {
    • [% issuecount %] Checkout(s)
    • [% IF relatives_issues_count %] -
    • Relatives' checkouts
    • +
    • [% relatives_issues_count %] Relatives' checkouts
    • [% END %]
    • Fines & Charges
    • diff --git a/koha-tmpl/intranet-tmpl/prog/js/members.js b/koha-tmpl/intranet-tmpl/prog/js/members.js index 3ea7868..06e90d9 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/members.js +++ b/koha-tmpl/intranet-tmpl/prog/js/members.js @@ -143,10 +143,6 @@ function Dopop(link) { var newin=window.open(link,'popup','width=600,height=400,resizable=no,toolbar=false,scrollbars=no,top'); } -function Dopopguarantor(link) { - var newin=window.open(link,'popup','width=800,height=500,resizable=no,toolbar=false,scrollbars=yes,top'); -} - function clear_entry(node) { var original = $(node).parent(); $("textarea", original).attr('value', ''); @@ -184,48 +180,11 @@ function update_category_code(category_code) { } function select_user(borrowernumber, borrower) { - var form = $('#entryform').get(0); - if (form.guarantorid.value) { - $("#contact-details, #quick_add_form #contact-details").find('a').remove(); - $("#contactname, #contactfirstname, #quick_add_form #contactname, #quick_add_form #contactfirstname").parent().find('span').remove(); - } + $('#guarantor_id').val(borrower.borrowernumber); + $('#guarantor_surname').val(borrower.surname); + $('#guarantor_firstname').val(borrower.firstname); - var id = borrower.borrowernumber; - form.guarantorid.value = id; - $('#contact-details, #quick_add_form #contact-details') - .show() - .find('span') - .after('' + id + ''); - - $(form.contactname) - .val(borrower.surname) - .before('' + borrower.surname + '').get(0).type = 'hidden'; - $("#quick_add_form #contactname").val(borrower.surname).before(''+borrower.surname+'' + borrower.firstname + '').get(0).type = 'hidden'; - $("#quick_add_form #contactfirstname").val(borrower.firstname).before(''+borrower.firstname+'You typed in the wrong characters in the box before submitting. Please try again. [% END %] - [% IF borrower.guarantorid && !Koha.Preference('OPACPrivacy') && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] + [% IF patron.guarantor_relationships && !Koha.Preference('OPACPrivacy') && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %]
      Privacy
        @@ -108,7 +108,12 @@ - Your guarantor is [% guarantor.firstname %] [% guarantor.surname %] + Guaranteed by + [% FOREACH gr IN patron.guarantor_relationships %] + [% SET g = gr.guarantor %] + [% g.firstname || gr.firstname %] [% g.surname || gr.surname %] + [%- IF ! loop.last %], [% END %] + [% END %]
      diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-privacy.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-privacy.tt index 38ca4fa..c86cbc0 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-privacy.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-privacy.tt @@ -69,7 +69,7 @@ - [% IF borrower.guarantorid && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] + [% IF borrower.guarantor_relationships && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %]
      - Your guarantor is [% borrower.guarantor.firstname %] [% borrower.guarantor.surname %] + Guaranteed by + [% FOREACH gr IN borrower.guarantor_relationships %] + [% SET g = gr.guarantor %] + [% g.firstname || gr.firstname %] [% g.surname || gr.surname %] + [%- IF ! loop.last %], [% END %] + [% END %]
      [% END %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt index ef24771..b8356b4 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt @@ -369,24 +369,24 @@ Using this account is not recommended because some parts of Koha will not functi [% FOREACH r IN relatives %] - [% FOREACH i IN r.issues %] + [% FOREACH c IN r.checkouts %] - [% i.item.biblio.title %][% IF ( i.item.enumchron ) %] [% i.item.enumchron %][% END %] + [% c.item.biblio.title %][% IF ( c.item.enumchron ) %] [% c.item.enumchron %][% END %] - [% i.date_due | $KohaDates %] + [% c.date_due | $KohaDates %] - [% i.item.barcode %] + [% c.item.barcode %] - [% i.item.itemcallnumber %] + [% c.item.itemcallnumber %] diff --git a/members/deletemem.pl b/members/deletemem.pl index 9ab49fb..24857c7 100755 --- a/members/deletemem.pl +++ b/members/deletemem.pl @@ -78,11 +78,10 @@ my $issues = GetPendingIssues($member); # FIXME: wasteful call when really, my $countissues = scalar(@$issues); my $bor = C4::Members::GetMember( borrowernumber => $member ); +my $patron = Koha::Patrons->find( $member ); my $flags = C4::Members::patronflags( $bor ); my $userenv = C4::Context->userenv; - - if ($bor->{category_type} eq "S") { unless(C4::Auth::haspermission($userenv->{'id'},{'staffaccess'=>1})) { print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=$member&error=CANT_DELETE_STAFF"); @@ -107,8 +106,7 @@ if (C4::Context->preference("IndependentBranches")) { my $op = $input->param('op') || 'delete_confirm'; my $dbh = C4::Context->dbh; -my $is_guarantor = $dbh->selectrow_array("SELECT COUNT(*) FROM borrowers WHERE guarantorid=?", undef, $member); -if ( $op eq 'delete_confirm' or $countissues > 0 or $flags->{'CHARGES'} or $is_guarantor or $deletelocal == 0) { +if ( $op eq 'delete_confirm' or $countissues > 0 or $flags->{'CHARGES'} or $patron->guarantee_relationships()->count() or $deletelocal == 0) { my $patron_image = Koha::Patron::Images->find($bor->{borrowernumber}); $template->param( picture => 1 ) if $patron_image; @@ -128,7 +126,7 @@ if ( $op eq 'delete_confirm' or $countissues > 0 or $flags->{'CHARGES'} or $is_ phone => $bor->{'phone'}, email => $bor->{'email'}, branchcode => $bor->{'branchcode'}, - activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), + activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), RoutingSerials => C4::Context->preference('RoutingSerials'), ); if ($countissues >0) { @@ -137,14 +135,14 @@ if ( $op eq 'delete_confirm' or $countissues > 0 or $flags->{'CHARGES'} or $is_ if ($flags->{'CHARGES'} ne '') { $template->param(charges => $flags->{'CHARGES'}->{'amount'}); } - if ($is_guarantor) { - $template->param(guarantees => 1); + if ( $patron->guarantee_relationships->count ) { + $template->param( guarantees => 1 ); } if ($deletelocal == 0) { $template->param(keeplocal => 1); } # This is silly written but reflect the same conditions as above - if ( not $countissues > 0 and not $flags->{CHARGES} ne '' and not $is_guarantor and not $deletelocal == 0 ) { + if ( not $countissues > 0 and not $flags->{CHARGES} ne '' and not $patron->guarantee_relationships->count and not $deletelocal == 0 ) { $template->param( op => 'delete_confirm', csrf_token => Koha::Token->new->generate_csrf( diff --git a/members/memberentry.pl b/members/memberentry.pl index 2fcaa72..e6f2dd0 100755 --- a/members/memberentry.pl +++ b/members/memberentry.pl @@ -81,7 +81,6 @@ if ( C4::Context->preference('SMSSendDriver') eq 'Email' ) { $template->param( sms_providers => \@providers ); } -my $guarantorid = $input->param('guarantorid'); my $borrowernumber = $input->param('borrowernumber'); my $actionType = $input->param('actionType') || ''; my $modify = $input->param('modify'); @@ -98,13 +97,25 @@ $nodouble = 1 if ($op eq 'modify' or $op eq 'duplicate'); # FIXME hack to rep # isn't a duplicate. Marking FIXME because this # script needs to be refactored. my $nok = $input->param('nok'); -my $guarantorinfo = $input->param('guarantorinfo'); my $step = $input->param('step') || 0; my @errors; my $borrower_data; my $NoUpdateLogin; my $userenv = C4::Context->userenv; +## Deal with guarantor stuff +my $patron = Koha::Patrons->find($borrowernumber); +$template->param( relationships => scalar $patron->guarantor_relationships ) if $patron; + +my $guarantor_id = $input->param('guarantor_id'); +my $guarantor = Koha::Patrons->find( $guarantor_id ) if $guarantor_id; +$template->param( guarantor => $guarantor ); + +my @delete_guarantor = $input->param('delete_guarantor'); +foreach my $id ( @delete_guarantor ) { + my $r = Koha::Patron::Relationships->find( $id ); + $r->delete() if $r; +} ## Deal with debarments $template->param( @@ -141,14 +152,14 @@ $template->param("minPasswordLength" => $minpw); my $check_BorrowerMandatoryField=C4::Context->preference("BorrowerMandatoryField"); my @field_check=split(/\|/,$check_BorrowerMandatoryField); foreach (@field_check) { - $template->param( "mandatory$_" => 1); + $template->param( "mandatory$_" => 1 ); } # function to designate unwanted fields my $check_BorrowerUnwantedField=C4::Context->preference("BorrowerUnwantedField"); @field_check=split(/\|/,$check_BorrowerUnwantedField); foreach (@field_check) { next unless m/\w/o; - $template->param( "no$_" => 1); + $template->param( "no$_" => 1 ); } $template->param( "add" => 1 ) if ( $op eq 'add' ); $template->param( "quickadd" => 1 ) if ( $quickadd ); @@ -242,25 +253,6 @@ if ( ( $op eq 'insert' ) and !$nodouble ) { } } - #recover all data from guarantor address phone ,fax... -if ( $guarantorid ) { - if (my $guarantordata=GetMember(borrowernumber => $guarantorid)) { - $category_type = $guarantordata->{categorycode} eq 'I' ? 'P' : 'C'; - $guarantorinfo=$guarantordata->{'surname'}." , ".$guarantordata->{'firstname'}; - $newdata{'contactfirstname'}= $guarantordata->{'firstname'}; - $newdata{'contactname'} = $guarantordata->{'surname'}; - $newdata{'contacttitle'} = $guarantordata->{'title'}; - if ( $op eq 'add' ) { - foreach (qw(streetnumber address streettype address2 - zipcode country city state phone phonepro mobile fax email emailpro branchcode - B_streetnumber B_streettype B_address B_address2 - B_city B_state B_zipcode B_country B_email B_phone)) { - $newdata{$_} = $guarantordata->{$_}; - } - } - } -} - ###############test to take the right zipcode, country and city name ############## # set only if parameter was passed from the form $newdata{'city'} = $input->param('city') if defined($input->param('city')); @@ -403,6 +395,7 @@ if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ if ($op eq 'insert'){ # we know it's not a duplicate borrowernumber or there would already be an error $borrowernumber = &AddMember(%newdata); + add_guarantors( $borrowernumber, $input ); $newdata{'borrowernumber'} = $borrowernumber; # If 'AutoEmailOpacUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode. @@ -500,6 +493,7 @@ if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ # updating any columns in the borrowers table, # which can happen if we're only editing the # patron attributes or messaging preferences sections + add_guarantors( $borrowernumber, $input ); if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) { C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes); } @@ -600,11 +594,10 @@ foreach my $category_type (qw(C A S P I X)) { 'categoryloop' => \@categoryloop }; } - -$template->param('typeloop' => \@typeloop, - no_categories => $no_categories); -if($no_categories){ $no_add = 1; } - +$template->param( + typeloop => \@typeloop, + no_categories => $no_categories, +); my $cities = Koha::Cities->search( {}, { order_by => 'city_name' } ); my $roadtypes = C4::Koha::GetAuthorisedValues( 'ROADTYPE' ); @@ -629,24 +622,27 @@ while (@relationships) { push(@relshipdata, \%row); } -my %flags = ( 'gonenoaddress' => ['gonenoaddress' ], - 'lost' => ['lost']); +my %flags = ( + 'gonenoaddress' => ['gonenoaddress'], + 'lost' => ['lost'] +); - my @flagdata; -foreach (keys(%flags)) { - my $key = $_; - my %row = ('key' => $key, - 'name' => $flags{$key}[0]); - if ($data{$key}) { - $row{'yes'}=' checked'; - $row{'no'}=''; - } - else { - $row{'yes'}=''; - $row{'no'}=' checked'; - } - push @flagdata,\%row; +foreach ( keys(%flags) ) { + my $key = $_; + my %row = ( + 'key' => $key, + 'name' => $flags{$key}[0] + ); + if ( $data{$key} ) { + $row{'yes'} = ' checked'; + $row{'no'} = ''; + } + else { + $row{'yes'} = ''; + $row{'no'} = ' checked'; + } + push @flagdata, \%row; } # get Branch Loop @@ -722,7 +718,7 @@ if (C4::Context->preference('EnhancedMessagingPreferences')) { $template->param(TalkingTechItivaPhone => C4::Context->preference("TalkingTechItivaPhoneNotification")); } -$template->param( "showguarantor" => ($category_type=~/A|I|S|X/) ? 0 : 1); # associate with step to know where you are +$template->param( "show_guarantor" => ( $category_type =~ /A|I|S|X/ ) ? 0 : 1 ); # associate with step to know where you are $debug and warn "memberentry step: $step"; $template->param(%data); $template->param( "step_$step" => 1) if $step; # associate with step to know where u are @@ -737,18 +733,16 @@ $template->param( "op$op" => 1); $template->param( - nodouble => $nodouble, - borrowernumber => $borrowernumber, #register number - guarantorid => ($borrower_data->{'guarantorid'} || $guarantorid), - relshiploop => \@relshipdata, - btitle=> $default_borrowertitle, - guarantorinfo => $guarantorinfo, - flagloop => \@flagdata, - category_type =>$category_type, - modify => $modify, - nok => $nok,#flag to know if an error - NoUpdateLogin => $NoUpdateLogin, - ); + nodouble => $nodouble, + borrowernumber => $borrowernumber, #register number + relshiploop => \@relshipdata, + btitle => $default_borrowertitle, + flagloop => \@flagdata, + category_type => $category_type, + modify => $modify, + nok => $nok, #flag to know if an error + NoUpdateLogin => $NoUpdateLogin, +); # Generate CSRF token $template->param( @@ -869,6 +863,42 @@ sub patron_attributes_form { } +sub add_guarantors { + my ( $borrowernumber, $input ) = @_; + + my @new_guarantor_id = scalar $input->param('new_guarantor_id'); + my @new_guarantor_surname = scalar $input->param('new_guarantor_surname'); + my @new_guarantor_firstname = scalar $input->param('new_guarantor_firstname'); + my @new_guarantor_relationship = scalar $input->param('new_guarantor_relationship'); + + for ( my $i = 0 ; $i < scalar @new_guarantor_id; $i++ ) { + my $guarantor_id = $new_guarantor_id[$i]; + my $surname = $new_guarantor_surname[$i]; + my $firstname = $new_guarantor_firstname[$i]; + my $relationship = $new_guarantor_relationship[$i]; + + if ($guarantor_id) { + Koha::Patron::Relationship->new( + { + guarantee_id => $borrowernumber, + guarantor_id => $guarantor_id, + relationship => $relationship + } + )->store(); + } + elsif ($surname) { + Koha::Patron::Relationship->new( + { + guarantee_id => $borrowernumber, + surname => $surname, + firstname => $firstname, + relationship => $relationship + } + )->store(); + } + } +} + # Local Variables: # tab-width: 8 # End: diff --git a/members/moremember.pl b/members/moremember.pl index 55b0901..1fc39f1 100755 --- a/members/moremember.pl +++ b/members/moremember.pl @@ -165,24 +165,22 @@ if ( $category_type eq 'C') { $template->param( 'catcode' => $patron_categories->next ) if $patron_categories->count == 1; } -my $patron = Koha::Patrons->find($data->{borrowernumber}); +my $patron = Koha::Patrons->find( $data->{borrowernumber} ); my @relatives; -if ( my $guarantor = $patron->guarantor ) { - $template->param( guarantor => $guarantor ); - push @relatives, $guarantor->borrowernumber; - push @relatives, $_->borrowernumber for $patron->siblings; -} elsif ( $patron->contactname || $patron->contactfirstname ) { - $template->param( - guarantor => { - firstname => $patron->contactfirstname, - surname => $patron->contactname, - } - ); -} else { - my @guarantees = $patron->guarantees; - $template->param( guarantees => \@guarantees ); - push @relatives, $_->borrowernumber for @guarantees; +my $guarantor_relationships = $patron->guarantor_relationships; +my @guarantees = $patron->guarantee_relationships->guarantees; +my @guarantors = $guarantor_relationships->guarantors; +if (@guarantors) { + push( @relatives, $_->id ) for @guarantors; + push( @relatives, $_->id ) for $patron->siblings(); } +else { + push( @relatives, $_->id ) for @guarantees; +} +$template->param( + guarantor_relationships => $guarantor_relationships, + guarantees => \@guarantees, +); my $relatives_issues_count = Koha::Database->new()->schema()->resultset('Issue') @@ -341,7 +339,6 @@ $template->param( quickslip => $quickslip, housebound_role => $patron->housebound_role, privacy_guarantor_checkouts => $data->{'privacy_guarantor_checkouts'}, - activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), AutoResumeSuspendedHolds => C4::Context->preference('AutoResumeSuspendedHolds'), SuspendHoldsIntranet => C4::Context->preference('SuspendHoldsIntranet'), RoutingSerials => C4::Context->preference('RoutingSerials'), diff --git a/members/update-child.pl b/members/update-child.pl index 5d50d93..17ace87 100755 --- a/members/update-child.pl +++ b/members/update-child.pl @@ -34,6 +34,7 @@ use C4::Auth; use C4::Output; use C4::Members; use Koha::Patron::Categories; +use Koha::Patrons; # use Smart::Comments; @@ -54,7 +55,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( my $borrowernumber = $input->param('borrowernumber'); my $catcode = $input->param('catcode'); my $cattype = $input->param('cattype'); -my $catcode_multi = $input->param('catcode_multi'); +my $catcode_multi = $input->param('catcode_multi'); my $op = $input->param('op'); if ( $op eq 'multi' ) { @@ -69,25 +70,29 @@ if ( $op eq 'multi' ) { ); output_html_with_http_headers $input, $cookie, $template->output; } - elsif ( $op eq 'update' ) { - my $member = GetMember('borrowernumber'=>$borrowernumber); - $member->{'guarantorid'} = 0; - $member->{'categorycode'} = $catcode; - my $borcat = Koha::Patron::Categories->find($catcode); - $member->{'category_type'} = $borcat->category_type; - $member->{'description'} = $borcat->description; - delete $member->{password}; - ModMember(%$member); + my $patron = Koha::Patrons->find($borrowernumber); + $_->delete() for $patrons->guarantor_relationships(); + + my $patron_hashref = patron->unblessed(); + my $borcat = GetBorrowercategory($catcode); + $patron_hashref->{'category_type'} = $borcat->{'category_type'}; + $patron_hashref->{'categorycode'} = $catcode; + $patron_hashref->{'description'} = $borcat->{'description'}; + delete $patron_hashref->{password}; + ModMember(%$patron_hashref); - if ( $catcode_multi ) { + if ($catcode_multi) { $template->param( - SUCCESS => 1, - borrowernumber => $borrowernumber, - ); + SUCCESS => 1, + borrowernumber => $borrowernumber, + ); output_html_with_http_headers $input, $cookie, $template->output; - } else { - print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=$borrowernumber"); + } + else { + print $input->redirect( + "/cgi-bin/koha/members/moremember.pl?borrowernumber=$borrowernumber" + ); } } diff --git a/misc/cronjobs/j2a.pl b/misc/cronjobs/j2a.pl index ba90ad0..3a1a3cf 100755 --- a/misc/cronjobs/j2a.pl +++ b/misc/cronjobs/j2a.pl @@ -163,12 +163,12 @@ $verbose and print "The age limit for category $fromcat is $agelimit\n"; my $itsyourbirthday = "$year-$mon-$mday"; if ( not $noaction ) { + # Start a transaction since we need to delete from relationships and update borrowers atomically + $dbh->{AutoCommit} = 0; + if ($mybranch) { #yep, we received a specific branch to work on. $verbose and print "Looking for patrons of $mybranch to update from $fromcat to $tocat that were born before $itsyourbirthday\n"; - my $query = qq| - UPDATE borrowers - SET guarantorid ='0', - categorycode = ? + my $where = qq| WHERE dateofbirth <= ? AND dateofbirth != '0000-00-00' AND branchcode = ? @@ -177,10 +177,28 @@ if ( not $noaction ) { FROM categories WHERE category_type = 'C' AND categorycode = ? - )|; + ) + |; + + my $query = qq| + DELETE relationships FROM relationships + LEFT JOIN borrowers ON ( borrowers.borrowernumber = relationships.guarantee_id ) + $where + |; my $sth = $dbh->prepare($query); + $sth->execute( $itsyourbirthday, $mybranch, $fromcat ) + or ( $dbh->rollback && die "can't execute" ); + + $query = qq| + UPDATE borrowers + SET categorycode = ? + $where + |; + $sth = $dbh->prepare($query); my $res = $sth->execute( $tocat, $itsyourbirthday, $mybranch, $fromcat ) - or die "can't execute"; + or ( $dbh->rollback && die "can't execute" ); + + $dbh->commit; if ( $res eq '0E0' ) { print "No patrons updated\n"; @@ -191,10 +209,7 @@ if ( not $noaction ) { } else { # branch was not supplied, processing all branches $verbose and print "Looking in all branches for patrons to update from $fromcat to $tocat that were born before $itsyourbirthday\n"; - my $query = qq| - UPDATE borrowers - SET guarantorid = '0', - categorycode = ? + my $where = qq| WHERE dateofbirth <= ? AND dateofbirth!='0000-00-00' AND categorycode IN ( @@ -202,10 +217,27 @@ if ( not $noaction ) { FROM categories WHERE category_type = 'C' AND categorycode = ? - )|; + ) + |; + + my $query = qq| + DELETE relationships FROM relationships + LEFT JOIN borrowers ON ( borrowers.borrowernumber = relationships.guarantee_id ) + $where + |; my $sth = $dbh->prepare($query); + $sth->execute( $itsyourbirthday, $fromcat ) + or ( $dbh->rollback && die "can't execute" ); + + $query = qq| + UPDATE borrowers + SET categorycode = ? + $where + |; + $sth = $dbh->prepare($query); my $res = $sth->execute( $tocat, $itsyourbirthday, $fromcat ) - or die "can't execute"; + or ( $dbh->rollback && die "can't execute" ); + $dbh->commit; if ( $res eq '0E0' ) { print "No patrons updated\n"; @@ -267,6 +299,7 @@ else { my $sth = $dbh->prepare($query); $sth->execute( $itsyourbirthday, $fromcat ) or die "Couldn't execute statement: " . $sth->errstr; + $dbh->commit; while ( my @res = $sth->fetchrow_array() ) { my $firstname = $res[0]; diff --git a/opac/opac-memberentry.pl b/opac/opac-memberentry.pl index c1610a1..c826d2c 100755 --- a/opac/opac-memberentry.pl +++ b/opac/opac-memberentry.pl @@ -282,7 +282,6 @@ elsif ( $action eq 'edit' ) { #Display logged in borrower's data $template->param( borrower => $borrower, - guarantor => scalar Koha::Patrons->find($borrowernumber)->guarantor(), hidden => GetHiddenFields( $mandatory, 'modification' ), csrf_token => Koha::Token->new->generate_csrf({ id => Encode::encode( 'UTF-8', $borrower->{userid} ), @@ -301,7 +300,8 @@ my $captcha = random_string("CCCCC"); $template->param( captcha => $captcha, - captcha_digest => md5_base64($captcha) + captcha_digest => md5_base64($captcha), + patron => Koha::Patrons->find( $borrowernumber ), ); output_html_with_http_headers $cgi, $cookie, $template->output, undef, { force_no_caching => 1 }; diff --git a/opac/opac-user.pl b/opac/opac-user.pl index 04a94c0..c7bb854 100755 --- a/opac/opac-user.pl +++ b/opac/opac-user.pl @@ -36,6 +36,7 @@ use C4::Letters; use Koha::DateUtils; use Koha::Holds; use Koha::Database; +use Koha::Patrons; use Koha::Patron::Messages; use Koha::Patron::Discharge; use Koha::Patrons; @@ -68,6 +69,8 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( } ); +my $patron = Koha::Patrons->find( $borrowernumber ); + my %renewed = map { $_ => 1 } split( ':', $query->param('renewed') ); my $show_priority; @@ -316,14 +319,12 @@ my $patron_messages = Koha::Patron::Messages->search( if ( C4::Context->preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') || C4::Context->preference('AllowStaffToSetCheckoutsVisibilityForGuarantor') ) { - my @relatives = - Koha::Database->new()->schema()->resultset("Borrower")->search( - { - privacy_guarantor_checkouts => 1, - 'me.guarantorid' => $borrowernumber - }, - { prefetch => [ { 'issues' => { 'item' => 'biblio' } } ] } - ); + my @relatives; + # Filter out guarantees that don't want guarantor to see checkouts + foreach my $gr ( $patron->guarantee_relationships() ) { + my $g = $gr->guarantee; + push( @relatives, $g ) if $g->privacy_guarantor_checkouts; + } $template->param( relatives => \@relatives ); } diff --git a/t/Patron.t b/t/Patron.t index c32de10..fb0c251 100755 --- a/t/Patron.t +++ b/t/Patron.t @@ -85,12 +85,7 @@ my $patron = Koha::Patron->new( lost => '0', debarred => '2015-04-19', debarredcomment => 'You are debarred', - contactname => 'myContactname', - contactfirstname => 'myContactfirstname', - contacttitle => 'myContacttitle', - guarantorid => '123454321', borrowernotes => 'borrowernotes', - relationship => 'myRelationship', sex => 'M', password => 'hfkurhfe976634èj!', flags => '55555', @@ -115,7 +110,7 @@ my $patron = Koha::Patron->new( # patron Accessor tests subtest 'Accessor tests' => sub { - plan tests => 65; + plan tests => 60; is( $patron->borrowernumber, '12345', 'borrowernumber accessor returns correct value' ); is( $patron->cardnumber, '1234567890', 'cardnumber accessor returns correct value' ); is( $patron->surname, 'mySurname', 'surname accessor returns correct value' ); @@ -156,12 +151,7 @@ subtest 'Accessor tests' => sub { is( $patron->lost, '0', 'lost accessor returns correct value' ); is( $patron->debarred, '2015-04-19', 'debarred accessor returns correct value' ); is( $patron->debarredcomment, 'You are debarred', 'debarredcomment accessor returns correct value' ); - is( $patron->contactname, 'myContactname', 'contactname accessor returns correct value' ); - is( $patron->contactfirstname, 'myContactfirstname', 'contactfirstname accessor returns correct value' ); - is( $patron->contacttitle, 'myContacttitle', 'contacttitle accessor returns correct value' ); - is( $patron->guarantorid, '123454321', 'guarantorid accessor returns correct value' ); is( $patron->borrowernotes, 'borrowernotes', 'borrowernotes accessor returns correct value' ); - is( $patron->relationship, 'myRelationship', 'relationship accessor returns correct value' ); is( $patron->sex, 'M', 'sex accessor returns correct value' ); is( $patron->password, 'hfkurhfe976634èj!', 'password accessor returns correct value' ); is( $patron->flags, '55555', 'flags accessor returns correct value' ); @@ -185,7 +175,7 @@ subtest 'Accessor tests' => sub { # patron Set tests subtest 'Set tests' => sub { - plan tests => 65; + plan tests => 60; $patron->set( { @@ -229,12 +219,7 @@ subtest 'Set tests' => sub { lost => '1', debarred => '2016-04-19', debarredcomment => 'You are still debarred', - contactname => 'SmyContactname', - contactfirstname => 'SmyContactfirstname', - contacttitle => 'SmyContacttitle', - guarantorid => '223454321', borrowernotes => 'Sborrowernotes', - relationship => 'SmyRelationship', sex => 'F', password => 'zerzerzer#', flags => '666666', @@ -297,12 +282,7 @@ subtest 'Set tests' => sub { is( $patron->lost, '1', 'lost field set ok' ); is( $patron->debarred, '2016-04-19', 'debarred field set ok' ); is( $patron->debarredcomment, 'You are still debarred', 'debarredcomment field set ok' ); - is( $patron->contactname, 'SmyContactname', 'contactname field set ok' ); - is( $patron->contactfirstname, 'SmyContactfirstname', 'contactfirstname field set ok' ); - is( $patron->contacttitle, 'SmyContacttitle', 'contacttitle field set ok' ); - is( $patron->guarantorid, '223454321', 'guarantorid field set ok' ); is( $patron->borrowernotes, 'Sborrowernotes', 'borrowernotes field set ok' ); - is( $patron->relationship, 'SmyRelationship', 'relationship field set ok' ); is( $patron->sex, 'F', 'sex field set ok' ); is( $patron->password, 'zerzerzer#', 'password field set ok' ); is( $patron->flags, '666666', 'flags field set ok' ); diff --git a/t/db_dependent/Circulation.t b/t/db_dependent/Circulation.t index e3d4c8d..8eca935 100755 --- a/t/db_dependent/Circulation.t +++ b/t/db_dependent/Circulation.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 91; +use Test::More tests => 93; BEGIN { require_ok('C4::Circulation'); @@ -37,6 +37,7 @@ use C4::Overdues qw(UpdateFine CalcFine); use Koha::DateUtils; use Koha::Database; use Koha::Subscriptions; +use Koha::Patron; my $schema = Koha::Database->schema; $schema->storage->txn_begin; @@ -312,6 +313,12 @@ C4::Context->dbh->do("DELETE FROM accountlines"); $datedue = dt_from_string( $issue->date_due() ); is (defined $issue2, 1, "Item 2 checked out, due date: " . $issue2->date_due()); + my $patron = Koha::Patrons->find( $renewing_borrower->{borrowernumber} ); + my @checkouts = $patron->checkouts(); + is( @checkouts, 2, "Patron has 2 checkouts" ); + is( $checkouts[0]->borrowernumber, $patron->id, 'Checkout 1 patron matches' ); + is( $checkouts[1]->borrowernumber, $patron->id, 'Checkout 2 patron matches' ); + my $borrowing_borrowernumber = GetItemIssue($itemnumber)->{borrowernumber}; is ($borrowing_borrowernumber, $renewing_borrowernumber, "Item checked out to $renewing_borrower->{firstname} $renewing_borrower->{surname}"); diff --git a/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t b/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t index dc2c880..65db0ef 100644 --- a/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t +++ b/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t @@ -24,6 +24,7 @@ use t::lib::Mocks; use C4::Accounts qw( manualinvoice ); use C4::Circulation qw( CanBookBeIssued ); +use Koha::Patron::Relationship; my $schema = Koha::Database->new->schema; $schema->storage->txn_begin; @@ -48,12 +49,17 @@ my $patron = $builder->build( my $guarantee = $builder->build( { source => 'Borrower', - value => { - guarantorid => $patron->{borrowernumber}, - } } ); +my $r = Koha::Patron::Relationship->new( + { + guarantor_id => $patron->{borrowernumber}, + guarantee_id => $guarantee->{borrowernumber}, + relationship => 'parent', + } +)->store(); + t::lib::Mocks::mock_preference( 'NoIssuesChargeGuarantees', '5.00' ); my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $item->{barcode} ); diff --git a/t/db_dependent/Items.t b/t/db_dependent/Items.t index 9e25704..26fa3fe 100755 --- a/t/db_dependent/Items.t +++ b/t/db_dependent/Items.t @@ -466,7 +466,7 @@ subtest 'SearchItems test' => sub { subtest 'Koha::Item(s) tests' => sub { - plan tests => 5; + plan tests => 7; $schema->storage->txn_begin(); @@ -505,6 +505,10 @@ subtest 'Koha::Item(s) tests' => sub { is( ref($holdingbranch), 'Koha::Library', "Got Koha::Library from holding_branch method" ); is( $holdingbranch->branchcode(), $library2->{branchcode}, "Home branch code matches holdingbranch" ); + my $biblio = $item->biblio(); + is( ref($biblio), 'Koha::Biblio', "Got Koha::Biblio from biblio method" ); + is( $biblio->title(), 'Silence in the library', 'Title matches biblio title' ); + $schema->storage->txn_rollback; }; diff --git a/t/db_dependent/Koha/Patrons.t b/t/db_dependent/Koha/Patrons.t index 98e1f40..d97c258 100644 --- a/t/db_dependent/Koha/Patrons.t +++ b/t/db_dependent/Koha/Patrons.t @@ -30,6 +30,7 @@ use C4::Members; use Koha::Holds; use Koha::Patron; use Koha::Patrons; +use Koha::Patron::Relationship; use Koha::Database; use Koha::DateUtils; use Koha::Virtualshelves; @@ -79,23 +80,25 @@ subtest 'library' => sub { subtest 'guarantees' => sub { plan tests => 8; - my $guarantees = $new_patron_1->guarantees; - is( ref($guarantees), 'Koha::Patrons', 'Koha::Patron->guarantees should return a Koha::Patrons result set in a scalar context' ); - is( $guarantees->count, 0, 'new_patron_1 should have 0 guarantee' ); - my @guarantees = $new_patron_1->guarantees; - is( ref(\@guarantees), 'ARRAY', 'Koha::Patron->guarantees should return an array in a list context' ); + my $guarantees = $new_patron_1->guarantee_relationships; + is( ref($guarantees), 'Koha::Patron::Relationships', 'Koha::Patron->guarantees should return a Koha::Patrons result set in a scalar context' ); + is( $guarantees->count, 0, 'new_patron_1 should have 0 guarantee relationships' ); + my @guarantees = $new_patron_1->guarantee_relationships; + is( ref(\@guarantees), 'ARRAY', 'Koha::Patron->guarantee_relationships should return an array in a list context' ); is( scalar(@guarantees), 0, 'new_patron_1 should have 0 guarantee' ); - my $guarantee_1 = $builder->build({ source => 'Borrower', value => { guarantorid => $new_patron_1->borrowernumber }}); - my $guarantee_2 = $builder->build({ source => 'Borrower', value => { guarantorid => $new_patron_1->borrowernumber }}); + my $guarantee_1 = $builder->build({ source => 'Borrower' }); + my $relationship_1 = Koha::Patron::Relationship->new( { guarantor_id => $new_patron_1->id, guarantee_id => $guarantee_1->{borrowernumber} } )->store(); + my $guarantee_2 = $builder->build({ source => 'Borrower' }); + my $relationship_2 = Koha::Patron::Relationship->new( { guarantor_id => $new_patron_1->id, guarantee_id => $guarantee_2->{borrowernumber} } )->store(); - $guarantees = $new_patron_1->guarantees; - is( ref($guarantees), 'Koha::Patrons', 'Koha::Patron->guarantees should return a Koha::Patrons result set in a scalar context' ); + $guarantees = $new_patron_1->guarantee_relationships; + is( ref($guarantees), 'Koha::Patron::Relationships', 'Koha::Patron->guarantee_relationships should return a Koha::Patrons result set in a scalar context' ); is( $guarantees->count, 2, 'new_patron_1 should have 2 guarantees' ); - @guarantees = $new_patron_1->guarantees; - is( ref(\@guarantees), 'ARRAY', 'Koha::Patron->guarantees should return an array in a list context' ); + @guarantees = $new_patron_1->guarantee_relationships; + is( ref(\@guarantees), 'ARRAY', 'Koha::Patron->guarantee_relationships should return an array in a list context' ); is( scalar(@guarantees), 2, 'new_patron_1 should have 2 guarantees' ); - $_->delete for @guarantees; + map { $_->guarantee->delete } @guarantees; }; subtest 'category' => sub { @@ -109,15 +112,18 @@ subtest 'siblings' => sub { plan tests => 7; my $siblings = $new_patron_1->siblings; is( $siblings, undef, 'Koha::Patron->siblings should not crashed if the patron has no guarantor' ); - my $guarantee_1 = $builder->build( { source => 'Borrower', value => { guarantorid => $new_patron_1->borrowernumber } } ); + my $guarantee_1 = $builder->build( { source => 'Borrower' } ); + my $relationship_1 = Koha::Patron::Relationship->new( { guarantor_id => $new_patron_1->borrowernumber, guarantee_id => $guarantee_1->{borrowernumber} } )->store(); my $retrieved_guarantee_1 = Koha::Patrons->find($guarantee_1); $siblings = $retrieved_guarantee_1->siblings; is( ref($siblings), 'Koha::Patrons', 'Koha::Patron->siblings should return a Koha::Patrons result set in a scalar context' ); my @siblings = $retrieved_guarantee_1->siblings; is( ref( \@siblings ), 'ARRAY', 'Koha::Patron->siblings should return an array in a list context' ); is( $siblings->count, 0, 'guarantee_1 should not have siblings yet' ); - my $guarantee_2 = $builder->build( { source => 'Borrower', value => { guarantorid => $new_patron_1->borrowernumber } } ); - my $guarantee_3 = $builder->build( { source => 'Borrower', value => { guarantorid => $new_patron_1->borrowernumber } } ); + my $guarantee_2 = $builder->build( { source => 'Borrower' } ); + my $relationship_2 = Koha::Patron::Relationship->new( { guarantor_id => $new_patron_1->borrowernumber, guarantee_id => $guarantee_2->{borrowernumber} } )->store(); + my $guarantee_3 = $builder->build( { source => 'Borrower' } ); + my $relationship_3 = Koha::Patron::Relationship->new( { guarantor_id => $new_patron_1->borrowernumber, guarantee_id => $guarantee_3->{borrowernumber} } )->store(); $siblings = $retrieved_guarantee_1->siblings; is( $siblings->count, 2, 'guarantee_1 should have 2 siblings' ); is( $guarantee_2->{borrowernumber}, $siblings->next->borrowernumber, 'guarantee_2 should exist in the guarantees' ); diff --git a/t/db_dependent/Members.t b/t/db_dependent/Members.t index 3d24e44..5ee52d8 100755 --- a/t/db_dependent/Members.t +++ b/t/db_dependent/Members.t @@ -25,6 +25,7 @@ use Koha::Database; use Koha::Holds; use Koha::List::Patron; use Koha::Patrons; +use Koha::Patron::Relationship; use t::lib::Mocks; use t::lib::TestBuilder; @@ -39,9 +40,6 @@ my $builder = t::lib::TestBuilder->new; my $dbh = C4::Context->dbh; $dbh->{RaiseError} = 1; -# Remove invalid guarantorid's as long as we have no FK -$dbh->do("UPDATE borrowers b1 LEFT JOIN borrowers b2 ON b2.borrowernumber=b1.guarantorid SET b1.guarantorid=NULL where b1.guarantorid IS NOT NULL AND b2.borrowernumber IS NULL"); - my $library1 = $builder->build({ source => 'Branch', }); @@ -259,7 +257,6 @@ my $borrower1 = $builder->build({ categorycode=>'STAFFER', branchcode => $library3->{branchcode}, dateexpiry => '2015-01-01', - guarantorid=> undef, }, }); my $bor1inlist = $borrower1->{borrowernumber}; @@ -269,7 +266,6 @@ my $borrower2 = $builder->build({ categorycode=>'STAFFER', branchcode => $library3->{branchcode}, dateexpiry => '2015-01-01', - guarantorid=> undef, }, }); @@ -279,7 +275,6 @@ my $guarantee = $builder->build({ categorycode=>'KIDclamp', branchcode => $library3->{branchcode}, dateexpiry => '2015-01-01', - guarantorid=> undef, # will be filled later }, }); @@ -310,7 +305,7 @@ $patstodel = GetBorrowersToExpunge( {not_borrowed_since => '2016-01-02', patron_ ok( scalar(@$patstodel) == 1 && $patstodel->[0]->{'borrowernumber'} eq $bor2inlist,'Staff patron not deleted by last issue date'); ModMember( borrowernumber => $bor1inlist, categorycode => 'CIVILIAN' ); -ModMember( borrowernumber => $guarantee->{borrowernumber} ,guarantorid=>$bor1inlist ); +my $relationship = Koha::Patron::Relationship->new( { guarantor_id => $bor1inlist, guarantee_id => $guarantee->{borrowernumber} } )->store(); $patstodel = GetBorrowersToExpunge( {patron_list_id => $list1->patron_list_id()} ); ok( scalar(@$patstodel)== 1 && $patstodel->[0]->{'borrowernumber'} eq $bor2inlist,'Guarantor patron not deleted from list'); @@ -320,7 +315,8 @@ $patstodel = GetBorrowersToExpunge( {expired_before => '2015-01-02', patron_list ok( scalar(@$patstodel) == 1 && $patstodel->[0]->{'borrowernumber'} eq $bor2inlist,'Guarantor patron not deleted by expirationdate and list'); $patstodel = GetBorrowersToExpunge( {not_borrowed_since => '2016-01-02', patron_list_id => $list1->patron_list_id() } ); ok( scalar(@$patstodel) == 1 && $patstodel->[0]->{'borrowernumber'} eq $bor2inlist,'Guarantor patron not deleted by last issue date'); -ModMember( borrowernumber => $guarantee->{borrowernumber}, guarantorid=>'' ); + +$relationship->delete(); $builder->build({ source => 'Issue', @@ -348,9 +344,9 @@ is( scalar(@$patstodel),2,'Borrowers without issues deleted by last issue date') # Test GetBorrowersToExpunge and TrackLastPatronActivity $dbh->do(q|UPDATE borrowers SET lastseen=NULL|); -$builder->build({ source => 'Borrower', value => { lastseen => '2016-01-01 01:01:01', categorycode => 'CIVILIAN', guarantorid => undef } } ); -$builder->build({ source => 'Borrower', value => { lastseen => '2016-02-02 02:02:02', categorycode => 'CIVILIAN', guarantorid => undef } } ); -$builder->build({ source => 'Borrower', value => { lastseen => '2016-03-03 03:03:03', categorycode => 'CIVILIAN', guarantorid => undef } } ); +$builder->build({ source => 'Borrower', value => { lastseen => '2016-01-01 01:01:01', categorycode => 'CIVILIAN' } } ); +$builder->build({ source => 'Borrower', value => { lastseen => '2016-02-02 02:02:02', categorycode => 'CIVILIAN' } } ); +$builder->build({ source => 'Borrower', value => { lastseen => '2016-03-03 03:03:03', categorycode => 'CIVILIAN' } } ); $patstodel = GetBorrowersToExpunge( { last_seen => '1999-12-12' }); is( scalar @$patstodel, 0, 'TrackLastPatronActivity - 0 patrons must be deleted' ); $patstodel = GetBorrowersToExpunge( { last_seen => '2016-02-15' }); diff --git a/t/db_dependent/Patron/Relationships.t b/t/db_dependent/Patron/Relationships.t new file mode 100755 index 0000000..4aec07a --- /dev/null +++ b/t/db_dependent/Patron/Relationships.t @@ -0,0 +1,181 @@ +#!/usr/bin/perl + +# 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 3 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, see . + +use Modern::Perl; + +use Test::More tests => 67; + +use C4::Context; + +use t::lib::TestBuilder; + +BEGIN { + use_ok('Koha::Objects'); + use_ok('Koha::Patrons'); + use_ok('Koha::Patron::Relationship'); + use_ok('Koha::Patron::Relationships'); +} + +# Start transaction +my $dbh = C4::Context->dbh; +$dbh->{AutoCommit} = 0; +$dbh->{RaiseError} = 1; + +my $builder = t::lib::TestBuilder->new(); + +# Father +my $kyle = Koha::Patrons->find( + $builder->build( + { + source => 'Borrower', + value => { + firstname => 'Kyle', + surname => 'Hall', + } + } + )->{borrowernumber} +); + +# Mother +my $chelsea = Koha::Patrons->find( + $builder->build( + { + source => 'Borrower', + value => { + firstname => 'Chelsea', + surname => 'Hall', + } + } + )->{borrowernumber} +); + +# Children +my $daria = Koha::Patrons->find( + $builder->build( + { + source => 'Borrower', + value => { + firstname => 'Daria', + surname => 'Hall', + } + } + )->{borrowernumber} +); + +my $kylie = Koha::Patrons->find( + $builder->build( + { + source => 'Borrower', + value => { + firstname => 'Kylie', + surname => 'Hall', + } + } + )->{borrowernumber} +); + +Koha::Patron::Relationship->new({ guarantor_id => $kyle->id, guarantee_id => $daria->id, relationship => 'father' })->store(); +Koha::Patron::Relationship->new({ guarantor_id => $kyle->id, guarantee_id => $kylie->id, relationship => 'father' })->store(); +Koha::Patron::Relationship->new({ guarantor_id => $chelsea->id, guarantee_id => $daria->id, relationship => 'mother' })->store(); +Koha::Patron::Relationship->new({ guarantor_id => $chelsea->id, guarantee_id => $kylie->id, relationship => 'mother' })->store(); +Koha::Patron::Relationship->new({ firstname => 'John', surname => 'Hall', guarantee_id => $daria->id, relationship => 'grandfather' })->store(); +Koha::Patron::Relationship->new({ firstname => 'Debra', surname => 'Hall', guarantee_id => $daria->id, relationship => 'grandmother' })->store(); +Koha::Patron::Relationship->new({ firstname => 'John', surname => 'Hall', guarantee_id => $kylie->id, relationship => 'grandfather' })->store(); +Koha::Patron::Relationship->new({ firstname => 'Debra', surname => 'Hall', guarantee_id => $kylie->id, relationship => 'grandmother' })->store(); + +my @gr; + +@gr = $kyle->guarantee_relationships(); +is( @gr, 2, 'Found 2 guarantee relationships for father' ); +is( $gr[0]->guarantor_id, $kyle->id, 'Guarantor matches for first relationship' ); +is( $gr[0]->guarantee_id, $daria->id, 'Guarantee matches for first relationship' ); +is( $gr[0]->relationship, 'father', 'Relationship is father' ); +is( ref($gr[0]->guarantee), 'Koha::Patron', 'Method guarantee returns a Koha::Patron' ); +is( $gr[0]->guarantee->id, $daria->id, 'Koha::Patron returned is the correct guarantee' ); +is( ref($gr[0]->guarantor), 'Koha::Patron', 'Method guarantor returns a Koha::Patron' ); +is( $gr[0]->guarantor->id, $kyle->id, 'Koha::Patron returned is the correct guarantor' ); + +is( $gr[1]->guarantor_id, $kyle->id, 'Guarantor matches for first relationship' ); +is( $gr[1]->guarantee_id, $kylie->id, 'Guarantee matches for first relationship' ); +is( $gr[1]->relationship, 'father', 'Relationship is father' ); +is( ref($gr[1]->guarantee), 'Koha::Patron', 'Method guarantee returns a Koha::Patron' ); +is( $gr[1]->guarantee->id, $kylie->id, 'Koha::Patron returned is the correct guarantee' ); +is( ref($gr[1]->guarantor), 'Koha::Patron', 'Method guarantor returns a Koha::Patron' ); +is( $gr[1]->guarantor->id, $kyle->id, 'Koha::Patron returned is the correct guarantor' ); + +@gr = $chelsea->guarantee_relationships(); +is( @gr, 2, 'Found 2 guarantee relationships for mother' ); +is( $gr[0]->guarantor_id, $chelsea->id, 'Guarantor matches for first relationship' ); +is( $gr[0]->guarantee_id, $daria->id, 'Guarantee matches for first relationship' ); +is( $gr[0]->relationship, 'mother', 'Relationship is mother' ); +is( ref($gr[0]->guarantee), 'Koha::Patron', 'Method guarantee returns a Koha::Patron' ); +is( $gr[0]->guarantee->id, $daria->id, 'Koha::Patron returned is the correct guarantee' ); +is( ref($gr[0]->guarantor), 'Koha::Patron', 'Method guarantor returns a Koha::Patron' ); +is( $gr[0]->guarantor->id, $chelsea->id, 'Koha::Patron returned is the correct guarantor' ); + +is( $gr[1]->guarantor_id, $chelsea->id, 'Guarantor matches for first relationship' ); +is( $gr[1]->guarantee_id, $kylie->id, 'Guarantee matches for first relationship' ); +is( $gr[1]->relationship, 'mother', 'Relationship is mother' ); +is( ref($gr[1]->guarantee), 'Koha::Patron', 'Method guarantee returns a Koha::Patron' ); +is( $gr[1]->guarantee->id, $kylie->id, 'Koha::Patron returned is the correct guarantee' ); +is( ref($gr[1]->guarantor), 'Koha::Patron', 'Method guarantor returns a Koha::Patron' ); +is( $gr[1]->guarantor->id, $chelsea->id, 'Koha::Patron returned is the correct guarantor' ); + +@gr = $daria->guarantor_relationships(); +is( @gr, 4, 'Found 4 guarantor relationships for child' ); +is( $gr[0]->guarantor_id, $kyle->id, 'Guarantor matches for first relationship' ); +is( $gr[0]->guarantee_id, $daria->id, 'Guarantee matches for first relationship' ); +is( $gr[0]->relationship, 'father', 'Relationship is father' ); +is( ref($gr[0]->guarantee), 'Koha::Patron', 'Method guarantee returns a Koha::Patron' ); +is( $gr[0]->guarantee->id, $daria->id, 'Koha::Patron returned is the correct guarantee' ); +is( ref($gr[0]->guarantor), 'Koha::Patron', 'Method guarantor returns a Koha::Patron' ); +is( $gr[0]->guarantor->id, $kyle->id, 'Koha::Patron returned is the correct guarantor' ); + +is( $gr[1]->guarantor_id, $chelsea->id, 'Guarantor matches for first relationship' ); +is( $gr[1]->guarantee_id, $daria->id, 'Guarantee matches for first relationship' ); +is( $gr[1]->relationship, 'mother', 'Relationship is mother' ); +is( ref($gr[1]->guarantee), 'Koha::Patron', 'Method guarantee returns a Koha::Patron' ); +is( $gr[1]->guarantee->id, $daria->id, 'Koha::Patron returned is the correct guarantee' ); +is( ref($gr[1]->guarantor), 'Koha::Patron', 'Method guarantor returns a Koha::Patron' ); +is( $gr[1]->guarantor->id, $chelsea->id, 'Koha::Patron returned is the correct guarantor' ); + +is( $gr[2]->guarantor_id, undef, 'Grandfather has no id, not a Koha patron' ); +is( $gr[2]->firstname, 'John', 'Grandfather has first name of John' ); +is( $gr[2]->surname, 'Hall', 'Grandfather has surname of Hall' ); +is( $gr[2]->guarantor, undef, 'Calling guarantor method for Grandfather returns undef' ); + +is( $gr[3]->guarantor_id, undef, 'Grandmother has no id, not a Koha patron' ); +is( $gr[3]->firstname, 'Debra', 'Grandmother has first name of John' ); +is( $gr[3]->surname, 'Hall', 'Grandmother has surname of Hall' ); +is( $gr[3]->guarantor, undef, 'Calling guarantor method for Grandmother returns undef' ); + +my @siblings = $daria->siblings; +is( @siblings, 1, 'Method siblings called in list context returns list' ); +is( ref($siblings[0]), 'Koha::Patron', 'List contains a Koha::Patron' ); +is( $siblings[0]->firstname, 'Kylie', 'Sibling from list first name matches correctly' ); +is( $siblings[0]->surname, 'Hall', 'Sibling from list surname matches correctly' ); +is( $siblings[0]->id, $kylie->id, 'Sibling from list patron id matches correctly' ); + +my $siblings = $daria->siblings; +my $sibling = $siblings->next(); +is( ref($siblings), 'Koha::Patrons', 'Calling siblings in scalar context results in a Koha::Patrons object' ); +is( ref($sibling), 'Koha::Patron', 'Method next returns a Koha::Patron' ); +is( $sibling->firstname, 'Kylie', 'Sibling from scalar first name matches correctly' ); +is( $sibling->surname, 'Hall', 'Sibling from scalar surname matches correctly' ); +is( $sibling->id, $kylie->id, 'Sibling from scalar patron id matches correctly' ); + +1; diff --git a/tools/import_borrowers.pl b/tools/import_borrowers.pl index daf7d59..79a5ed9 100755 --- a/tools/import_borrowers.pl +++ b/tools/import_borrowers.pl @@ -320,6 +320,19 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) { } } + # Add a guarantor if we are given a relationship + if ( $borrower{relationship} ) { + Koha::Patron::Relationship->new( + { + guarantee_id => $borrowernumber, + relationship => $borrower{relationship}, + guarantor_id => $borrower{guarantorid} || undef, + firstname => $borrower{contactfirstname} || undef, + surname => $borrower{contactsurname} || undef, + } + )->store(); + } + if ($extended) { if ($ext_preserve) { my $old_attributes = GetBorrowerAttributes($borrowernumber); @@ -347,6 +360,19 @@ if ( $uploadborrowers && length($uploadborrowers) > 0 ) { ); } + # Add a guarantor if we are given a relationship + if ( $borrower{relationship} ) { + Koha::Patron::Relationship->new( + { + guarantee_id => $borrowernumber, + relationship => $borrower{relationship}, + guarantor_id => $borrower{guarantorid} || undef, + firstname => $borrower{contactfirstname} || undef, + surname => $borrower{contactsurname} || undef, + } + )->store(); + } + if ($extended) { SetBorrowerAttributes($borrowernumber, $patron_attributes); } -- 2.1.4