Bugzilla – Attachment 77077 Details for
Bug 14570
Make it possible to add multiple guarantors to a record
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14570: Make it possible to add multiple guarantors to a record
Bug-14570-Make-it-possible-to-add-multiple-guarant.patch (text/plain), 113.37 KB, created by
Kyle M Hall (khall)
on 2018-07-18 13:41:22 UTC
(
hide
)
Description:
Bug 14570: Make it possible to add multiple guarantors to a record
Filename:
MIME Type:
Creator:
Kyle M Hall (khall)
Created:
2018-07-18 13:41:22 UTC
Size:
113.37 KB
patch
obsolete
>From 86e5a2173a2d73820164e5c3c83547c31933b2da Mon Sep 17 00:00:00 2001 >From: Kyle M Hall <kyle@bywatersolutions.com> >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 > >Signed-off-by: Kim Peine <kmpeine@gmail.com> > >Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> >--- > C4/Auth_with_ldap.pm | 1 - > C4/Circulation.pm | 2 +- > C4/Members.pm | 16 +- > C4/SIP/ILS/Patron.pm | 1 - > Koha/Item.pm | 1 + > Koha/Object.pm | 8 +- > Koha/Patron.pm | 114 ++++-- > Koha/Patron/Relationship.pm | 73 ++++ > Koha/Patron/Relationships.pm | 94 +++++ > Koha/Patrons.pm | 12 - > Koha/Patrons/Import.pm | 16 + > Koha/Schema/Result/Borrower.pm | 6 - > Koha/Schema/Result/BorrowerRelationship.pm | 118 ++++++ > api/v1/swagger/definitions/patron.json | 4 - > circ/circulation.pl | 14 +- > installer/data/mysql/atomicupdate/bug_14570.sql | 17 + > installer/data/mysql/kohastructure.sql | 23 +- > koha-tmpl/intranet-tmpl/prog/en/columns.def | 1 - > .../prog/en/includes/members-toolbar.inc | 16 +- > .../prog/en/modules/circ/circulation.tt | 2 +- > .../prog/en/modules/members/memberentrygen.tt | 405 ++++++++++++--------- > .../prog/en/modules/members/moremember-brief.tt | 30 +- > .../prog/en/modules/members/moremember.tt | 19 +- > koha-tmpl/intranet-tmpl/prog/js/members.js | 92 +++-- > .../bootstrap/en/modules/opac-memberentry.tt | 11 +- > .../opac-tmpl/bootstrap/en/modules/opac-privacy.tt | 9 +- > .../opac-tmpl/bootstrap/en/modules/opac-user.tt | 10 +- > members/deletemem.pl | 6 +- > members/memberentry.pl | 115 +++--- > members/moremember.pl | 28 +- > members/update-child.pl | 21 +- > misc/cronjobs/j2a.pl | 58 ++- > opac/opac-memberentry.pl | 4 +- > opac/opac-user.pl | 17 +- > t/Patron.t | 24 +- > .../Circulation/NoIssuesChargeGuarantees.t | 25 +- > 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 | 167 +++++++++ > tools/import_borrowers.pl | 1 + > 41 files changed, 1141 insertions(+), 500 deletions(-) > create mode 100644 Koha/Patron/Relationship.pm > create mode 100644 Koha/Patron/Relationships.pm > create mode 100644 Koha/Schema/Result/BorrowerRelationship.pm > create mode 100644 installer/data/mysql/atomicupdate/bug_14570.sql > create mode 100755 t/db_dependent/Patron/Relationships.t > >diff --git a/C4/Auth_with_ldap.pm b/C4/Auth_with_ldap.pm >index bbb1094229..27d9aaebdd 100644 >--- a/C4/Auth_with_ldap.pm >+++ b/C4/Auth_with_ldap.pm >@@ -463,7 +463,6 @@ C4::Auth - Authenticates Koha users > | contactname | mediumtext | YES | | NULL | | > | contactfirstname | text | YES | | NULL | | > | contacttitle | text | YES | | NULL | | >- | guarantorid | int(11) | YES | MUL | NULL | | > | borrowernotes | mediumtext | YES | | NULL | | > | relationship | varchar(100) | YES | | NULL | | > | ethnicity | varchar(50) | YES | | NULL | | >diff --git a/C4/Circulation.pm b/C4/Circulation.pm >index 8e1bdc49fc..83dfded5b1 100644 >--- a/C4/Circulation.pm >+++ b/C4/Circulation.pm >@@ -758,7 +758,7 @@ sub CanBookBeIssued { > my $no_issues_charge_guarantees = C4::Context->preference("NoIssuesChargeGuarantees"); > $no_issues_charge_guarantees = undef unless looks_like_number( $no_issues_charge_guarantees ); > if ( defined $no_issues_charge_guarantees ) { >- my @guarantees = $patron->guarantees(); >+ my @guarantees = map { $_->guarantee } $patron->guarantee_relationships(); > my $guarantees_non_issues_charges; > foreach my $g ( @guarantees ) { > $guarantees_non_issues_charges += $g->account->non_issues_charges; >diff --git a/C4/Members.pm b/C4/Members.pm >index a901a961bc..4817e2b5fa 100644 >--- a/C4/Members.pm >+++ b/C4/Members.pm >@@ -198,7 +198,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 ) { > $guarantees_non_issues_charges += $g->account->non_issues_charges; >@@ -317,7 +317,6 @@ sub ModMember { > $new_borrower->{dateexpiry} ||= undef if exists $new_borrower->{dateexpiry}; > $new_borrower->{debarred} ||= undef if exists $new_borrower->{debarred}; > $new_borrower->{sms_provider_id} ||= undef if exists $new_borrower->{sms_provider_id}; >- $new_borrower->{guarantorid} ||= undef if exists $new_borrower->{guarantorid}; > > my $patron = Koha::Patrons->find( $new_borrower->{borrowernumber} ); > >@@ -450,7 +449,6 @@ sub AddMember { > $data{'dateofbirth'} = undef if ( not $data{'dateofbirth'} ); > $data{'debarred'} = undef if ( not $data{'debarred'} ); > $data{'sms_provider_id'} = undef if ( not $data{'sms_provider_id'} ); >- $data{'guarantorid'} = undef if ( not $data{'guarantorid'} ); > > # get only the columns of Borrower > # FIXME Do we really need this check? >@@ -657,18 +655,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/C4/SIP/ILS/Patron.pm b/C4/SIP/ILS/Patron.pm >index 23c576493f..868f4d6b17 100644 >--- a/C4/SIP/ILS/Patron.pm >+++ b/C4/SIP/ILS/Patron.pm >@@ -616,7 +616,6 @@ __END__ > | contactname | mediumtext | YES | | NULL | | > | contactfirstname | text | YES | | NULL | | > | contacttitle | text | YES | | NULL | | >-| guarantorid | int(11) | YES | MUL | NULL | | > | borrowernotes | mediumtext | YES | | NULL | | > | relationship | varchar(100) | YES | | NULL | | > | ethnicity | varchar(50) | YES | | NULL | | >diff --git a/Koha/Item.pm b/Koha/Item.pm >index bea05f8317..ee76bf6f67 100644 >--- a/Koha/Item.pm >+++ b/Koha/Item.pm >@@ -28,6 +28,7 @@ use C4::Context; > use Koha::Checkouts; > use Koha::IssuingRules; > use Koha::Item::Transfer; >+use Koha::Biblios; > use Koha::Patrons; > use Koha::Libraries; > >diff --git a/Koha/Object.pm b/Koha/Object.pm >index e35ff0b85e..436ec1df63 100644 >--- a/Koha/Object.pm >+++ b/Koha/Object.pm >@@ -72,8 +72,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 35cfce4ca1..825fae0c88 100644 >--- a/Koha/Patron.pm >+++ b/Koha/Patron.pm >@@ -27,15 +27,16 @@ use Text::Unaccent qw( unac_string ); > 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 Koha::Club::Enrollments; > use Koha::Account; >@@ -141,41 +142,61 @@ 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 { >- my ( $self ) = @_; >- >- return unless $self->guarantorid(); >- >- return Koha::Patrons->find( $self->guarantorid() ); >-} >- > sub image { > my ( $self ) = @_; > > return scalar Koha::Patron::Images->find( $self->borrowernumber ); > } > >+=head3 library >+ >+Returns a Koha::Library object representing the patron's home library. >+ >+=cut >+ > sub library { > my ( $self ) = @_; > return Koha::Library->_new_from_dbic($self->_result->branchcode); > } > >-=head3 guarantees >+=head3 guarantor_relationships > >-Returns the guarantees (list of Koha::Patron) of this patron >+Returns Koha::Patron::Relationships object for this patron's guarantors >+ >+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::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::Patrons->search( { guarantorid => $self->borrowernumber } ); >+ return Koha::Patron::Relationships->search( { guarantor_id => $self->id } ); > } > > =head3 housebound_profile >@@ -213,23 +234,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 merge_with >@@ -951,6 +971,7 @@ my $is_child = $patron->is_child > Return true if the patron has a category with a type Child (C) > > =cut >+ > sub is_child { > my( $self ) = @_; > return $self->category->category_type eq 'C' ? 1 : 0; >@@ -1032,6 +1053,35 @@ sub generate_userid { > > } > >+ >+=head3 add_guarantor >+ >+ my @relationships = $patron->add_guarantor( >+ { >+ borrowernumber => $borrowernumber, >+ relationships => $relationship, >+ } >+ ); >+ >+ Adds a new guarantor to a patron. >+ >+=cut >+ >+sub add_guarantor { >+ my ( $self, $params ) = @_; >+ >+ my $guarantor_id = $params->{guarantor_id}; >+ my $relationship = $params->{relationship}; >+ >+ return Koha::Patron::Relationship->new( >+ { >+ guarantee_id => $self->id, >+ guarantor_id => $guarantor_id, >+ relationship => $relationship >+ } >+ )->store(); >+} >+ > =head2 Internal methods > > =head3 _type >diff --git a/Koha/Patron/Relationship.pm b/Koha/Patron/Relationship.pm >new file mode 100644 >index 0000000000..24994aa2b7 >--- /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 scalar Koha::Patrons->find( $self->guarantor_id ); >+} >+ >+=head3 guarantee >+ >+Returns the Koha::Patron object for the guarantee >+ >+=cut >+ >+sub guarantee { >+ my ( $self ) = @_; >+ >+ return scalar Koha::Patrons->find( $self->guarantee_id ); >+} >+ >+=head3 type >+ >+=cut >+ >+sub _type { >+ return 'BorrowerRelationship'; >+} >+ >+1; >diff --git a/Koha/Patron/Relationships.pm b/Koha/Patron/Relationships.pm >new file mode 100644 >index 0000000000..981ceac5b7 >--- /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 'BorrowerRelationship'; >+} >+ >+sub object_class { >+ return 'Koha::Patron::Relationship'; >+} >+ >+1; >diff --git a/Koha/Patrons.pm b/Koha/Patrons.pm >index 0d2d9ec6b4..bba01b533d 100644 >--- a/Koha/Patrons.pm >+++ b/Koha/Patrons.pm >@@ -124,18 +124,6 @@ sub search_upcoming_membership_expires { > ); > } > >-=head3 guarantor >- >-Returns a Koha::Patron object for this borrower's guarantor >- >-=cut >- >-sub guarantor { >- my ( $self ) = @_; >- >- return Koha::Patrons->find( $self->guarantorid() ); >-} >- > =head3 search_patrons_to_anonymise > > my $patrons = Koha::Patrons->search_patrons_to_anonymise( { before => $older_than_date, [ library => $library ] } ); >diff --git a/Koha/Patrons/Import.pm b/Koha/Patrons/Import.pm >index fbf9701e92..4d17bde3bf 100644 >--- a/Koha/Patrons/Import.pm >+++ b/Koha/Patrons/Import.pm >@@ -213,6 +213,11 @@ sub import_patrons { > next LINE; > } > >+ my $relationship = $borrower{relationship}; >+ my $guarantor_id = $borrower{guarantor_id}; >+ delete $borrower{relationship}; >+ delete $borrower{guarantor_id}; >+ > if ($borrowernumber) { > > # borrower exists >@@ -348,6 +353,17 @@ sub import_patrons { > ); > } > } >+ >+ # Add a guarantor if we are given a relationship >+ if ( $guarantor_id ) { >+ Koha::Patron::Relationship->new( >+ { >+ guarantee_id => $borrowernumber, >+ relationship => $relationship, >+ guarantor_id => $guarantor_id, >+ } >+ )->store(); >+ } > } > > return { >diff --git a/Koha/Schema/Result/Borrower.pm b/Koha/Schema/Result/Borrower.pm >index 8663b8654b..e88fdd2b18 100644 >--- a/Koha/Schema/Result/Borrower.pm >+++ b/Koha/Schema/Result/Borrower.pm >@@ -1419,12 +1419,6 @@ __PACKAGE__->many_to_many("ordernumbers", "aqorder_users", "ordernumber"); > # Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-07-06 14:12:40 > # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LaQWPXzF1Amzt8fgEEyHdg > >-__PACKAGE__->belongs_to( >- "guarantor", >- "Koha::Schema::Result::Borrower", >- { borrowernumber => "guarantorid" }, >-); >- > __PACKAGE__->add_columns( > '+lost' => { is_boolean => 1 }, > '+gonenoaddress' => { is_boolean => 1 } >diff --git a/Koha/Schema/Result/BorrowerRelationship.pm b/Koha/Schema/Result/BorrowerRelationship.pm >new file mode 100644 >index 0000000000..88cef4f294 >--- /dev/null >+++ b/Koha/Schema/Result/BorrowerRelationship.pm >@@ -0,0 +1,118 @@ >+use utf8; >+package Koha::Schema::Result::BorrowerRelationship; >+ >+# Created by DBIx::Class::Schema::Loader >+# DO NOT MODIFY THE FIRST PART OF THIS FILE >+ >+=head1 NAME >+ >+Koha::Schema::Result::BorrowerRelationship >+ >+=cut >+ >+use strict; >+use warnings; >+ >+use base 'DBIx::Class::Core'; >+ >+=head1 TABLE: C<borrower_relationships> >+ >+=cut >+ >+__PACKAGE__->table("borrower_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 >+ >+=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 }, >+); >+ >+=head1 PRIMARY KEY >+ >+=over 4 >+ >+=item * L</id> >+ >+=back >+ >+=cut >+ >+__PACKAGE__->set_primary_key("id"); >+ >+=head1 RELATIONS >+ >+=head2 guarantee >+ >+Type: belongs_to >+ >+Related object: L<Koha::Schema::Result::Borrower> >+ >+=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<Koha::Schema::Result::Borrower> >+ >+=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.07046 @ 2018-07-18 10:52:59 >+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:R8RThgcrct40Zq0UMW3TWQ >+ >+ >+# You can replace this text with custom code or comments, and it will be preserved on regeneration >+1; >diff --git a/api/v1/swagger/definitions/patron.json b/api/v1/swagger/definitions/patron.json >index 5d6ccd82c0..549b470f0b 100644 >--- a/api/v1/swagger/definitions/patron.json >+++ b/api/v1/swagger/definitions/patron.json >@@ -159,10 +159,6 @@ > "readOnly": true, > "description": "If any restriction applies to the patron" > }, >- "guarantor_id": { >- "type": ["integer", "null"], >- "description": "patron_id used for children or professionals to link them to guarantor or organizations" >- }, > "staff_notes": { > "type": ["string", "null"], > "description": "a note on the patron's account" >diff --git a/circ/circulation.pl b/circ/circulation.pl >index 1617584cf4..e82d036cb8 100755 >--- a/circ/circulation.pl >+++ b/circ/circulation.pl >@@ -571,14 +571,12 @@ my $view = $batch > : 'circview'; > > my @relatives; >-if ( $borrowernumber ) { >- if ( $patron ) { >- if ( my $guarantor = $patron->guarantor ) { >- push @relatives, $guarantor->borrowernumber; >- push @relatives, $_->borrowernumber for $patron->siblings; >- } else { >- push @relatives, $_->borrowernumber for $patron->guarantees; >- } >+if ( $patron ) { >+ if ( my @guarantors = $patron->guarantor_relationships()->guarantors() ) { >+ push( @relatives, $_->id ) for @guarantors; >+ push( @relatives, $_->id ) for $patron->siblings(); >+ } else { >+ push( @relatives, $_->id ) for $patron->guarantee_relationships()->guarantees(); > } > } > my $relatives_issues_count = >diff --git a/installer/data/mysql/atomicupdate/bug_14570.sql b/installer/data/mysql/atomicupdate/bug_14570.sql >new file mode 100644 >index 0000000000..b0bb359d43 >--- /dev/null >+++ b/installer/data/mysql/atomicupdate/bug_14570.sql >@@ -0,0 +1,17 @@ >+CREATE TABLE `borrower_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, >+ 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 borrower_relationships ( guarantor_id, guarantee_id, relationship ) SELECT guarantorid, borrowernumber, relationship FROM borrowers WHERE guarantorid IS NOT NULL; >+ >+ALTER TABLE borrowers DROP guarantorid; >+ALTER TABLE deletedborrowers DROP guarantorid; >+ALTER TABLE borrowermodification DROP guarantorid; >diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql >index 20b1a5716e..f590ed4d77 100644 >--- a/installer/data/mysql/kohastructure.sql >+++ b/installer/data/mysql/kohastructure.sql >@@ -582,7 +582,6 @@ CREATE TABLE `deletedborrowers` ( -- stores data related to the patrons/borrower > `contactname` LONGTEXT, -- used for children and profesionals to include surname or last name of guarantor or organization name > `contactfirstname` MEDIUMTEXT, -- used for children to include first name of guarantor > `contacttitle` MEDIUMTEXT, -- used for children to include title (Mr., Mrs., etc) of guarantor >- `guarantorid` int(11) default NULL, -- borrowernumber used for children or professionals to link them to guarantors or organizations > `borrowernotes` LONGTEXT, -- 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 guarantor > `sex` varchar(1) default NULL, -- patron/borrower's gender >@@ -1612,7 +1611,6 @@ CREATE TABLE `borrowers` ( -- this table includes information about your patrons > `contactname` LONGTEXT, -- used for children and profesionals to include surname or last name of guarantor or organization name > `contactfirstname` MEDIUMTEXT, -- used for children to include first name of guarantor > `contacttitle` MEDIUMTEXT, -- used for children to include title (Mr., Mrs., etc) of guarantor >- `guarantorid` int(11) default NULL, -- borrowernumber used for children or professionals to link them to guarantors or organizations > `borrowernotes` LONGTEXT, -- 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 guarantor > `sex` varchar(1) default NULL, -- patron/borrower's gender >@@ -1647,7 +1645,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` (191)), > KEY `firstname_idx` (`firstname` (191)), > KEY `othernames_idx` (`othernames` (191)), >@@ -3428,12 +3425,7 @@ CREATE TABLE IF NOT EXISTS `borrower_modifications` ( > `lost` tinyint(1) DEFAULT NULL, > `debarred` date DEFAULT NULL, > `debarredcomment` varchar(255) DEFAULT NULL, >- `contactname` LONGTEXT, >- `contactfirstname` MEDIUMTEXT, >- `contacttitle` MEDIUMTEXT, >- `guarantorid` int(11) DEFAULT NULL, > `borrowernotes` LONGTEXT, >- `relationship` varchar(100) DEFAULT NULL, > `sex` varchar(1) DEFAULT NULL, > `password` varchar(30) DEFAULT NULL, > `flags` int(11) DEFAULT NULL, >@@ -4113,6 +4105,21 @@ CREATE TABLE IF NOT EXISTS club_fields ( > ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; > > -- >+-- Table structure for table 'guarantors_guarantees' >+-- >+ >+DROP TABLE IF EXISTS borrower_relationships; >+CREATE TABLE `borrower_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, >+ 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=utf8mb4 COLLATE=utf8mb4_unicode_ci; >+ >+-- > -- Table structure for table `illrequests` > -- > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/columns.def b/koha-tmpl/intranet-tmpl/prog/en/columns.def >index 21c74f2017..10ecd7cbd1 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/columns.def >+++ b/koha-tmpl/intranet-tmpl/prog/en/columns.def >@@ -7,7 +7,6 @@ > <field name="borrowers.othernames">Other name</field> > <field name="borrowers.sex">Gender</field> > <field name="borrowers.relationship">Relationship</field> >-<field name="borrowers.guarantorid">Guarantor borrower number</field> > <field name="borrowers.streetnumber">Street number</field> > <field name="borrowers.streettype">Street type</field> > <field name="borrowers.address">Address</field> >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 1897af77ae..3043c25bbb 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc >@@ -6,21 +6,17 @@ > [% SET NorwegianPatronDBEnable = Koha.Preference( 'NorwegianPatronDBEnable' ) %] > <div id="toolbar" class="btn-toolbar"> > [% IF CAN_user_borrowers_edit_borrowers %] >- [% IF ( guarantor ) %] >- <a id="editpatron" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% patron.borrowernumber %]&guarantorid=[% guarantor.borrowernumber %]&categorycode=[% patron.categorycode %]"> >- [% ELSE %] >- <a id="editpatron" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% patron.borrowernumber %]&categorycode=[% patron.categorycode %]"> >- [% END %] >- <i class="fa fa-pencil"></i> Edit</a> >+ <a id="editpatron" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/memberentry.pl?op=modify&destination=circ&borrowernumber=[% patron.borrowernumber %]&categorycode=[% patron.categorycode %]"> >+ <i class="fa fa-pencil"></i> Edit >+ </a> > [% END %] > > [% IF CAN_user_borrowers_edit_borrowers %] > [% IF patron.is_adult AND Koha.Preference("borrowerRelationship") %] >- <a id="addchild" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/memberentry.pl?op=add&guarantorid=[% patron.borrowernumber %]"><i class="fa fa-plus"></i> Add child</a> >- [% END %] >- [% IF CAN_user_borrowers_edit_borrowers %] >- <a id="changepassword" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/member-password.pl?member=[% patron.borrowernumber %]"><i class="fa fa-lock"></i> Change password</a> >+ <a id="addchild" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/memberentry.pl?op=add&guarantor_id=[% patron.borrowernumber %]"><i class="fa fa-plus"></i> Add child</a> > [% END %] >+ >+ <a id="changepassword" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/member-password.pl?member=[% patron.borrowernumber %]"><i class="fa fa-lock"></i> Change password</a> > <a id="duplicate" class="btn btn-default btn-sm" href="/cgi-bin/koha/members/memberentry.pl?op=duplicate&borrowernumber=[% patron.borrowernumber %]&categorycode=[% patron.categorycode %]"><i class="fa fa-copy"></i> Duplicate</a> > [% END %] > >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 a6e6ba00fa..b2d8922ef7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt >@@ -807,7 +807,7 @@ No patron matched <span class="ex">[% message | html %]</span> > </li> > > [% IF relatives_issues_count %] >- <li><a id="relatives-issues-tab" href="#relatives-issues">Relatives' checkouts</a></li> >+ <li><a id="relatives-issues-tab" href="#relatives-issues">[% relatives_issues_count %] Relatives' checkouts</a></li> > [% END %] > > <li> >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 36353607b3..e57a1deac3 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/memberentrygen.tt >@@ -1,4 +1,5 @@ > [% USE Asset %] >+[% USE To %] > [% USE Koha %] > [% USE KohaDates %] > [% USE Branches %] >@@ -297,113 +298,124 @@ > </fieldset> > [% END # hide fieldset %] > >-[% IF ( showguarantor ) %] >- <input type="hidden" id="guarantorid" name="guarantorid" value="[% guarantorid %]" /> >- [% UNLESS step_6 %] >- <input type="hidden" name="branchcode" value="[% branchcode %]" /> >- [% END %] >- <fieldset id="memberentry_guarantor" class="rows"> >- <legend id="guarantor_lgd">Guarantor information</legend> >- <ol> >-[% IF ( P ) %] >- [% IF ( guarantorid ) %] >- <li id="contact-details"> >- [% ELSE %] >- <li id="contact-details" style="display: none"> >- [% END %] >- <span class="label">Organization #:</span> [% IF ( guarantorid ) %] <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guarantorid %]" target="blank">[% guarantorid %]</a>[% END %] >- </li> >- <li> >- <label for="contactname">Organization name: </label> >- [% IF ( guarantorid ) %] >- <span>[% contactname %]</span> >- <input name="contactname" id="contactname" type="hidden" size="20" value="[% contactname | html %]" /> >- [% ELSE %] >- <input name="contactname" id="contactname" type="text" size="20" value="[% contactname | html %]" /> >- [% END %] >- </li> >-[% ELSE %] >- [% IF ( C ) %] >- [% IF ( guarantorid ) %] >- <li id="contact-details"> >- [% ELSE %] >- <li id="contact-details" style="display: none"> >- [% END %] >- <span class="label">Patron #:</span> >- [% IF guarantorid %] >- [% IF logged_in_user.can_see_patron_infos( guarantor ) %] >- <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guarantorid %]" target="blank">[% guarantorid | html %]</a> >- [% ELSE %] >- [% guarantorid | html %] >- [% END %] >- [% END %] >- </li> >- [% UNLESS nocontactname %] >- <li> >- <label for="contactname">Surname: </label> >- [% IF ( guarantorid ) %] >- <span>[% contactname %]</span> >- <input name="contactname" id="contactname" type="hidden" size="20" value="[% contactname | html %]" /> >- [% ELSE %] >- <input name="contactname" id="contactname" type="text" size="20" value="[% contactname | html %]" /> >- [% END %] >- </li> >- [% END %] >- [% UNLESS nocontactfirstname %] >- <li> >- <label for="contactfirstname">First name: </label> >- [% IF ( guarantorid ) %] >- <span>[% contactfirstname %]</span> >- <input name="contactfirstname" id="contactfirstname" type="hidden" size="20" value="[% contactfirstname | html %]" /> >- [% ELSE %] >- <input name="contactfirstname" id="contactfirstname" type="text" size="20" value="[% contactfirstname | html %]" /> >- [% END %] >- </li> >- [% END %] >- [% IF ( relshiploop ) %] >- <li> >- <label for="relationship">Relationship: </label> >- <select name="relationship" id="relationship" > >- [% FOREACH relshiploo IN relshiploop %] >- [% IF ( relshiploo.selected ) %] >- <option value="[% relshiploo.relationship %]" selected="selected" >[% relshiploo.relationship %]</option> >- [% ELSE %] >- <option value="[% relshiploo.relationship %]">[% relshiploo.relationship %]</option> >- [% END %] >- [% END %] >- </select> >- </li> >- [% END %] >- [% END %] >-[% END %] >- <li> >- <span class="label"> </span> >- [% IF ( guarantorid ) %] >- <input id="guarantorsearch" type="button" value="Change" onclick="Dopopguarantor('guarantor_search.pl');" /> >- [% ELSE %] >- <input id="guarantorsearch" type="button" value="Set to patron" onclick="Dopopguarantor('guarantor_search.pl');" /> >- [% END %] >- <input id="guarantordelete" type="button" value="Delete" /> >- </li> >- [% IF guarantorid && Koha.Preference('AllowStaffToSetCheckoutsVisibilityForGuarantor') %] >- <li> >- <label for="privacy_guarantor_checkouts">Show checkouts to guarantor</label> >- <select name="privacy_guarantor_checkouts" id="privacy_guarantor_checkouts"> >- [% IF privacy_guarantor_checkouts %] >- <option value="0">No</option> >- <option value="1" selected>Yes</option> >- [% ELSE %] >- <option value="0" selected>No</option> >- <option value="1">Yes</option> >+[% IF show_guarantor || guarantor %] >+ [% SET possible_relationships = Koha.Preference('borrowerRelationship') %] >+ <fieldset class="rows"> >+ <legend>Guarantor information</legend> >+ >+ <span id="guarantor_relationships"> >+ [% FOREACH r IN relationships %] >+ <fieldset class="rows"> >+ <ol> >+ [% IF category_type == 'P' %] >+ <li id="contact-details"> >+ <span class="label">Organization #:</span> [% IF ( r.guarantor_id ) %] <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% r.guarantor_id %]" target="blank">[% r.guarantor_id %]</a>[% END %] >+ </li> >+ >+ <li> >+ <label for="guarantor_surname">Organization name: </label> >+ <span>[% r.guarantor.surname %]</span> >+ </li> >+ [% ELSE %] >+ <li id="contact-details"> >+ <span class="label">Patron #:</span> >+ <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% r.guarantor_id %]" target="blank">[% r.guarantor_id %]</a> >+ </li> >+ >+ [% IF r.guarantor.surname %] >+ <li> >+ <label for="guarantor_surname">Surname: </label> >+ <span>[% r.guarantor.surname %]</span> >+ </li> >+ [% END %] >+ >+ [% IF r.guarantor.firstname %] >+ <li> >+ <label for="guarantor_firstname">First name: </label> >+ <span>[% r.guarantor.firstname %]</span> >+ </li> >+ [% END %] >+ >+ <li> >+ <label for="relationship">Relationship: </label> >+ <span>[% r.relationship %]</span> >+ </li> >+ >+ <li> >+ <label for="delete_guarantor-[% r.id %]">Delete: </label> >+ <input type="checkbox" id="delete_guarantor-[% r.id %]" name="delete_guarantor" value="[% r.id %]" /> >+ </li> >+ [% END %] >+ </ol> >+ </fieldset> >+ [% END # END relationships foreach %] >+ </span> >+ >+ <fieldset class="rows guarantor" id="guarantor_template"> >+ <ol> >+ <li class="guarantor_id"> >+ <span class="label">Patron #:</span> >+ <span class="new_guarantor_id_text"></span> >+ <input type="hidden" class="new_guarantor_id" name="new_guarantor_id" value=""/> >+ </li> >+ >+ <li> >+ <label for="guarantor_surname">Surname: </label> >+ <span class="new_guarantor_surname_text"></span> >+ <input type="hidden" class="new_guarantor_surname" name="new_guarantor_surname" value=""/> >+ </li> >+ >+ <li> >+ <label for="guarantor_firstname">First name: </label> >+ <span class="new_guarantor_firstname_text"></span> >+ <input type="hidden" class="new_guarantor_firstname" name="new_guarantor_firstname" value=""/> >+ </li> >+ >+ <li> >+ <label for="guarantor_relationship">Relationship: </label> >+ <select class="new_guarantor_relationship" name="new_guarantor_relationship"> >+ [% FOREACH pr IN possible_relationships.split('\|') %] >+ <option value="[% pr %]">[% pr %]</option> >+ [% END %] >+ </select> >+ </li> >+ >+ <li> >+ <label for="guarantor_cancel"> </label> >+ <span><a href="#" class="guarantor_cancel">Cancel</a></span> >+ </li> >+ </ol> >+ </fieldset> >+ >+ <ol> >+ <input type="hidden" id="guarantor_id" value="" /> >+ <input name="guarantor_surname" id="guarantor_surname" type="hidden" /> >+ <input name="guarantor_firstname" id="guarantor_firstname" type="hidden" /> >+ >+ <li> >+ <a href="#" id="guarantor_search" class="btn btn-sm"><i class="fa fa-search"></i> Search</a> >+ </li> >+ >+ [% IF relationships && Koha.Preference('AllowStaffToSetCheckoutsVisibilityForGuarantor') %] >+ <li> >+ <label for="privacy_guarantor_checkouts">Show checkouts to guarantors</label> >+ <select name="privacy_guarantor_checkouts" id="privacy_guarantor_checkouts"> >+ [% IF privacy_guarantor_checkouts %] >+ <option value="0">No</option> >+ <option value="1" selected>Yes</option> >+ [% ELSE %] >+ <option value="0" selected>No</option> >+ <option value="1">Yes</option> >+ [% END %] >+ </select> >+ <div class="hint">Allow guarantors of this patron to view this patron's checkouts from the OPAC</div> >+ </li> > [% END %] >- </select> >- <div class="hint">Allow guarantor of this patron to view this patron's checkouts from the OPAC</div> >- </li> >- [% END %] >- </ol> >+ </ol> > </fieldset> >- > [% END %] >+ >+ > [% UNLESS noaddress && noaddress2 && nocity && nostate && nozipcode && nocountry %] > [% IF Koha.Preference( 'AddressFormat' ) %] > [% INCLUDE "member-main-address-style-${ Koha.Preference( 'AddressFormat' ) }.inc" %] >@@ -413,84 +425,132 @@ > [% END # nostreet && nocity etc group%] > > [% UNLESS nophone && nophonepro && nomobile && noemail && noemailpro && nofax %] >- <fieldset class="rows" id="memberentry_contact"> >- <legend id="contact_lgd">Contact</legend><ol> >- [% UNLESS nophone %] >- <li> >- [% IF ( mandatoryphone ) %] >- <label for="phone" class="required"> >- [% ELSE %] >- <label for="phone"> >- [% END %] >- Primary phone: </label> >- <input type="text" id="phone" name="phone" value="[% phone | html %]" /> >- [% IF ( mandatoryphone ) %]<span class="required">Required</span>[% END %]<div class="hint">Shows on transit slips</div> >+ <fieldset class="rows" id="memberentry_contact"> >+ <legend id="contact_lgd">Contact</legend><ol> > >- </li> >+ [% UNLESS nocontactname %] >+ <li> >+ [% IF ( mandatorycontactname ) %] >+ <label for="contactname" class="required"> >+ [% ELSE %] >+ <label for="contactname"> >+ [% END %] >+ Guarantor surname: </label> >+ <input type="text" id="contactname" name="contactname" value="[% contactname | html %]" /> >+ [% IF ( mandatorycontactname ) %]<span class="required">Required</span>[% END %]<div class="hint">Non-patron guarantor surname</div> >+ </li> > [% END %] >+ >+ [% UNLESS nocontactfirstname %] >+ <li> >+ [% IF ( mandatorycontactfirstname ) %] >+ <label for="contactfirstname" class="required"> >+ [% ELSE %] >+ <label for="contactfirstname"> >+ [% END %] >+ Guarantor first name: </label> >+ <input type="text" id="contactfirstname" name="contactfirstname" value="[% contactfirstname | html %]" /> >+ [% IF ( mandatorycontactfirstname ) %]<span class="required">Required</span>[% END %]<div class="hint">Non-patron guarantor first name</div> >+ </li> >+ [% END %] >+ >+ [% UNLESS norelationship %] >+ [% IF possible_relationships %] >+ <li> >+ <label for="relationship">Relationship: </label> >+ <select class="relationship" name="relationship"> >+ <option value=""></option> >+ [% FOREACH pr IN possible_relationships.split('\|') %] >+ [% IF pr == relationship %] >+ <option value="[% pr %]" selected="selected">[% pr %]</option> >+ [% ELSE %] >+ <option value="[% pr %]">[% pr %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ [% END %] >+ [% END %] >+ >+ [% UNLESS nophone %] >+ <li> >+ [% IF ( mandatoryphone ) %] >+ <label for="phone" class="required"> >+ [% ELSE %] >+ <label for="phone"> >+ [% END %] >+ Primary phone: </label> >+ <input type="text" id="phone" name="phone" value="[% phone | html %]" /> >+ [% IF ( mandatoryphone ) %]<span class="required">Required</span>[% END %]<div class="hint">Shows on transit slips</div> >+ </li> >+ [% END %] >+ > [% UNLESS nophonepro %] >- <li> >- [% IF ( mandatoryphonepro ) %] >- <label for="phonepro" class="required"> >- [% ELSE %] >- <label for="phonepro"> >- [% END %] >- Secondary phone: </label> >- <input type="text" id="phonepro" name="phonepro" value="[% phonepro | html %]" /> >- [% IF ( mandatoryphonepro ) %]<span class="required">Required</span>[% END %] >- </li> >+ <li> >+ [% IF ( mandatoryphonepro ) %] >+ <label for="phonepro" class="required"> >+ [% ELSE %] >+ <label for="phonepro"> >+ [% END %] >+ Secondary phone: </label> >+ <input type="text" id="phonepro" name="phonepro" value="[% phonepro | html %]" /> >+ [% IF ( mandatoryphonepro ) %]<span class="required">Required</span>[% END %] >+ </li> > [% END %] >+ > [% UNLESS nomobile %] >- <li> >- [% IF ( mandatorymobile ) %] >- <label for="mobile" class="required"> >- [% ELSE %] >- <label for="mobile"> >- [% END %] >- Other phone: </label> >- <input type="text" id="mobile" name="mobile" value="[% mobile | html %]" /> >- [% IF ( mandatorymobile ) %]<span class="required">Required</span>[% END %] >- </li> >+ <li> >+ [% IF ( mandatorymobile ) %] >+ <label for="mobile" class="required"> >+ [% ELSE %] >+ <label for="mobile"> >+ [% END %] >+ Other phone: </label> >+ <input type="text" id="mobile" name="mobile" value="[% mobile | html %]" /> >+ [% IF ( mandatorymobile ) %]<span class="required">Required</span>[% END %] >+ </li> > [% END %] >- [% UNLESS noemail %] >- <li> >- [% IF ( mandatoryemail ) %] >- <label for="email" class="required"> >- [% ELSE %] >- <label for="email"> >- [% END %] >- Primary email: </label> >- <input type="text" id="email" name="email" size="45" value="[% email | html %]" /> >- [% IF ( mandatoryemail ) %]<span class="required">Required</span>[% END %]<div class="hint">Shows on transit slips</div> > >- </li> >+ [% UNLESS noemail %] >+ <li> >+ [% IF ( mandatoryemail ) %] >+ <label for="email" class="required"> >+ [% ELSE %] >+ <label for="email"> >+ [% END %] >+ Primary email: </label> >+ <input type="text" id="email" name="email" size="45" value="[% email | html %]" /> >+ [% IF ( mandatoryemail ) %]<span class="required">Required</span>[% END %]<div class="hint">Shows on transit slips</div> >+ </li> > [% END %] >+ > [% UNLESS noemailpro %] >- <li> >- [% IF ( mandatoryemailpro ) %] >- <label for="emailpro" class="required"> >- [% ELSE %] >- <label for="emailpro"> >- [% END %] >- Secondary email: </label> >- <input type="text" id="emailpro" name="emailpro" size="45" value="[% emailpro | html %]" /> >- [% IF ( mandatoryemailpro ) %]<span class="required">Required</span>[% END %] >- </li> >+ <li> >+ [% IF ( mandatoryemailpro ) %] >+ <label for="emailpro" class="required"> >+ [% ELSE %] >+ <label for="emailpro"> >+ [% END %] >+ Secondary email: </label> >+ <input type="text" id="emailpro" name="emailpro" size="45" value="[% emailpro | html %]" /> >+ [% IF ( mandatoryemailpro ) %]<span class="required">Required</span>[% END %] >+ </li> > [% END %] >+ > [% UNLESS nofax %] >- <li> >- [% IF ( mandatoryfax ) %] >- <label for="fax" class="required"> >- [% ELSE %] >- <label for="fax"> >- [% END %] >- Fax: </label> >- <input type="text" id="fax" name="fax" value="[% fax | html %]" /> >- [% IF ( mandatoryfax ) %]<span class="required">Required</span>[% END %] >- </li> >+ <li> >+ [% IF ( mandatoryfax ) %] >+ <label for="fax" class="required"> >+ [% ELSE %] >+ <label for="fax"> >+ [% END %] >+ Fax: </label> >+ <input type="text" id="fax" name="fax" value="[% fax | html %]" /> >+ [% IF ( mandatoryfax ) %]<span class="required">Required</span>[% END %] >+ </li> > [% END %] >- </ol> >- </fieldset> >+ </ol> >+</fieldset> > [%END # hide fieldset %] > > <!-- ************************ STEP_1 *********************** --> >@@ -1193,6 +1253,11 @@ > update_category_code( category_code ); > } > [% END %] >+ >+ [% IF guarantor %] >+ select_user( '[% guarantor.borrowernumber %]', [% To.json( guarantor.unblessed ) %] ); >+ [% END %] >+ > }); > > function update_cardnumber_warning(size){ >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 0c2270ad05..e15f0e3c31 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 >@@ -42,16 +42,26 @@ > [% IF ( dateofbirth ) %]<li><span class="label">Date of birth:</span>[% dateofbirth | $KohaDates %]</li>[% END %] > [% IF ( sex ) %]<li><span class="label">Gender:</span>[% IF ( sex == 'F' ) %]Female[% ELSIF ( sex == 'M' ) %]Male[% ELSE %][% sex %][% END %]</li>[% END %][% END %] > [% END %] >- [% IF ( isguarantee ) %] >- [% IF ( guaranteeloop ) %] >- <li><span class="label">Guarantees:</span><ul>[% FOREACH guaranteeloo IN guaranteeloop %]<li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guaranteeloo.borrowernumber %]">[% guaranteeloo.name %] </a></li>[% END %]</ul></li> >- [% END %] >- [% ELSE %] >- [% IF ( guarantor.borrowernumber ) %] >- <li><span class="label">Guarantor:</span><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guarantor.borrowernumber %]">[% guarantor.surname %], [% guarantor.firstname %]</a></li> >- [% END %] >- [% END %] >- </ol> >+ >+ [% IF guarantees %] >+ <li> >+ <span class="label">Guarantees:</span> >+ <ul> >+ [% FOREACH guarantee IN guarantees %] >+ <li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guarantee.borrowernumber %]">[% guarantee.firstname %] [% guarantee.surname %]</a></li> >+ [% END %] >+ </ul> >+ </li> >+ [% ELSIF guarantor_relationships %] >+ [% FOREACH gr IN guarantor_relationships %] >+ <li> >+ <span class="label">Guarantor:</span> >+ [% SET guarantor = gr.guarantor %] >+ <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guarantor.id %]">[% guarantor.firstname %] [% guarantor.surname %]</a> >+ </li> >+ [% END %] >+ [% END %] >+ </ol> > </div> > </div> > </div> >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 cac919f1dd..86da08482c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >@@ -218,15 +218,16 @@ > [% END %] > </ul> > </li> >- [% ELSIF guarantor %] >- <li> >- <span class="label">Guarantor:</span> >- [% IF guarantor.borrowernumber AND logged_in_user.can_see_patron_infos( guarantor ) %] >- <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guarantor.borrowernumber %]">[% guarantor.firstname | html %] [% guarantor.surname | html %]</a> >- [% ELSE %] >- [% guarantor.firstname | html %] [% guarantor.surname | html %] >- [% END %] >- </li> >+ [% ELSIF guarantor_relationships %] >+ [% FOREACH gr IN guarantor_relationships %] >+ <li> >+ <span class="label">Guarantor:</span> >+ [% SET guarantor = gr.guarantor %] >+ [% IF logged_in_user.can_see_patron_infos( guarantor ) %] >+ <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% guarantor.id %]">[% guarantor.firstname | html %] [% guarantor.surname | html %]</a> >+ [% END %] >+ </li> >+ [% END %] > [% END %] > </ol> > </div> [% # /div.rows %] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/members.js b/koha-tmpl/intranet-tmpl/prog/js/members.js >index e586e60d23..7f1774e7df 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/members.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/members.js >@@ -129,10 +129,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', ''); >@@ -170,48 +166,38 @@ 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 fieldset = $('#guarantor_template').clone(); >+ fieldset.removeAttr('id'); >+ >+ var guarantor_id = $('#guarantor_id').val(); >+ if ( guarantor_id ) { >+ fieldset.find('.new_guarantor_id').first().val( guarantor_id ); >+ fieldset.find('.new_guarantor_id_text').first().text( guarantor_id ); >+ } else { >+ fieldset.find('.guarantor_id').first().hide(); > } >+ $('#guarantor_id').val(""); >+ >+ var guarantor_surname = $('#guarantor_surname').val(); >+ fieldset.find('.new_guarantor_surname').first().val( guarantor_surname ); >+ fieldset.find('.new_guarantor_surname_text').first().text( guarantor_surname ); >+ $('#guarantor_surname').val(""); >+ >+ var guarantor_firstname = $('#guarantor_firstname').val(); >+ fieldset.find('.new_guarantor_firstname').first().val( guarantor_firstname ); >+ fieldset.find('.new_guarantor_firstname_text').first().text( guarantor_firstname ); >+ $('#guarantor_firstname').val(""); > >- var id = borrower.borrowernumber; >- form.guarantorid.value = id; >- $('#contact-details, #quick_add_form #contact-details') >- .show() >- .find('span') >- .after('<a target="blank" href="/cgi-bin/koha/members/moremember.pl?borrowernumber=' + id + '">' + id + '</a>'); >- >- $(form.contactname) >- .val(borrower.surname) >- .before('<span>' + borrower.surname + '</span>').get(0).type = 'hidden'; >- $("#quick_add_form #contactname").val(borrower.surname).before('<span>'+borrower.surname+'</span.').attr({type:"hidden"}); >- $(form.contactfirstname,"#quick_add_form #contactfirstname") >- .val(borrower.firstname) >- .before('<span>' + borrower.firstname + '</span>').get(0).type = 'hidden'; >- $("#quick_add_form #contactfirstname").val(borrower.firstname).before('<span>'+borrower.firstname+'</span.').attr({type:"hidden"}); >- >- form.streetnumber.value = borrower.streetnumber; >- form.address.value = borrower.address; >- form.address2.value = borrower.address2; >- form.city.value = borrower.city; >- form.state.value = borrower.state; >- form.zipcode.value = borrower.zipcode; >- form.country.value = borrower.country; >- form.branchcode.value = borrower.branchcode; >- >- $("#quick_add_form #streetnumber").val(borrower.streetnumber); >- $("#quick_add_form #address").val(borrower.address); >- $("#quick_add_form #address2").val(borrower.address2); >- $("#quick_add_form #city").val(borrower.city); >- $("#quick_add_form #state").val(borrower.state); >- $("#quick_add_form #zipcode").val(borrower.zipcode); >- $("#quick_add_form #country").val(borrower.country); >- $("#quick_add_form select[name='branchcode']").val(borrower.branchcode); >- >- form.guarantorsearch.value = LABEL_CHANGE; >- $("#quick_add_form #guarantorsearch").val(LABEL_CHANGE); >+ var guarantor_relationship = $('#relationship').val(); >+ fieldset.find('.new_guarantor_relationship').first().val( guarantor_relationship ); >+ $('#relationship').find('option:eq(0)').prop('selected', true);; >+ >+ $('#guarantor_relationships').append( fieldset ); >+ fieldset.show(); > > return 0; > } >@@ -284,13 +270,17 @@ $(document).ready(function(){ > }); > > $("fieldset.rows input, fieldset.rows select").addClass("noEnterSubmit"); >- $("#guarantordelete").click(function() { >- $("#quick_add_form #contact-details, #contact-details").hide().find('a').remove(); >- $("#quick_add_form #guarantorid, #quick_add_form #contactname, #quick_add_form #contactfirstname, #guarantorid, #contactname, #contactfirstname").each(function () { this.value = ""; }); >- $("#quick_add_form #contactname, #quick_add_form #contactfirstname, #contactname, #contactfirstname") >- .each(function () { this.type = 'text'; }) >- .parent().find('span').remove(); >- $("#quick_add_form #guarantorsearch, #guarantorsearch").val(LABEL_SET_TO_PATRON); >+ >+ $('#guarantor_template').hide(); >+ >+ $('#guarantor_search').on('click', function(e) { >+ e.preventDefault(); >+ var newin = window.open('guarantor_search.pl','popup','width=600,height=400,resizable=no,toolbar=false,scrollbars=yes,top'); >+ }); >+ >+ $('#guarantor_relationships').on('click', '.guarantor_cancel', function(e) { >+ e.preventDefault(); >+ $(this).parents('fieldset').first().remove(); > }); > > $(document.body).on('change','select[name="select_city"]',function(){ >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >index 7b391960af..3c83be47f7 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt >@@ -99,7 +99,7 @@ > <div class="alert">You typed in the wrong characters in the box before submitting. Please try again.</div> > [% END %] > >- [% IF borrower.guarantorid && !Koha.Preference('OPACPrivacy') && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] >+ [% IF patron.guarantor_relationships && !Koha.Preference('OPACPrivacy') && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] > <fieldset class="rows" id="memberentry_privacy"> > <legend id="privacy_legend">Privacy</legend> > <ol> >@@ -118,7 +118,12 @@ > <span id="update_privacy_guarantor_checkouts_message" class="alert" style="display:none"></span> > </span> > <span class="hint"> >- Your guarantor is <i>[% guarantor.firstname %] [% guarantor.surname %]</i> >+ Guaranteed by >+ [% FOREACH gr IN patron.guarantor_relationships %] >+ [% SET g = gr.guarantor %] >+ [% g.firstname %] [% g.surname %] >+ [%- IF ! loop.last %], [% END %] >+ [% END %] > </span> > </li> > </ol> >@@ -997,7 +1002,7 @@ > } > }); > >- [% IF borrower.guarantorid && !Koha.Preference('OPACPrivacy') && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] >+ [% IF patron.guarantor_relationships && !Koha.Preference('OPACPrivacy') && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] > $('#update_privacy_guarantor_checkouts').click( function() { > $.post( "/cgi-bin/koha/svc/patron/show_checkouts_to_relatives", { privacy_guarantor_checkouts: $('#privacy_guarantor_checkouts').val() }, null, 'json') > .done(function( data ) { >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 143f4e023b..71a4724d54 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-privacy.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-privacy.tt >@@ -71,7 +71,7 @@ > </select> > </div> > >- [% IF borrower.guarantorid && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] >+ [% IF borrower.guarantor_relationships && Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %] > <div> > <label for="privacy_guarantor_checkouts">Allow your guarantor to view your current checkouts?</label> > <select name="privacy_guarantor_checkouts"> >@@ -84,7 +84,12 @@ > [% END %] > </select> > <span class="hint"> >- Your guarantor is <i>[% borrower.guarantor.firstname %] [% borrower.guarantor.surname %]</i> >+ Guaranteed by >+ [% FOREACH gr IN borrower.guarantor_relationships %] >+ [% SET g = gr.guarantor %] >+ [% g.firstname %] [% g.surname %] >+ [%- IF ! loop.last %], [% END %] >+ [% END %] > </span> > </div> > [% 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 fb904159fe..134f7230d2 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt >@@ -428,24 +428,24 @@ > > <tbody> > [% FOREACH r IN relatives %] >- [% FOREACH i IN r.issues %] >+ [% FOREACH c IN r.checkouts %] > <tr> > <td> > <a href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% i.item.biblio.biblionumber %]"> >- [% i.item.biblio.title %][% IF ( i.item.enumchron ) %] [% i.item.enumchron %][% END %] >+ [% c.item.biblio.title %][% IF ( c.item.enumchron ) %] [% c.item.enumchron %][% END %] > </a> > </td> > > <td> >- [% i.date_due | $KohaDates %] >+ [% c.date_due | $KohaDates %] > </td> > > <td> >- [% i.item.barcode %] >+ [% c.item.barcode %] > </td> > > <td> >- [% i.item.itemcallnumber %] >+ [% c.item.itemcallnumber %] > </td> > > <td> >diff --git a/members/deletemem.pl b/members/deletemem.pl >index bc0c92441b..ee99317e24 100755 >--- a/members/deletemem.pl >+++ b/members/deletemem.pl >@@ -109,7 +109,7 @@ if ( $patron->is_child ) { > > 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); >+my $is_guarantor = $patron->guarantee_relationships->count; > if ( $op eq 'delete_confirm' or $countissues > 0 or $charges or $is_guarantor or $deletelocal == 0) { > > $template->param( >@@ -121,8 +121,8 @@ if ( $op eq 'delete_confirm' or $countissues > 0 or $charges or $is_guarantor or > if ( $charges > 0 ) { > $template->param(charges => $charges); > } >- if ($is_guarantor) { >- $template->param(guarantees => 1); >+ if ( $is_guarantor ) { >+ $template->param( guarantees => 1 ); > } > if ($deletelocal == 0) { > $template->param(keeplocal => 1); >diff --git a/members/memberentry.pl b/members/memberentry.pl >index f10002a80b..a954779548 100755 >--- a/members/memberentry.pl >+++ b/members/memberentry.pl >@@ -83,7 +83,6 @@ if ( C4::Context->preference('SMSSendDriver') eq 'Email' ) { > $template->param( sms_providers => \@providers ); > } > >-my $guarantorid = $input->param('guarantorid'); > my $actionType = $input->param('actionType') || ''; > my $modify = $input->param('modify'); > my $delete = $input->param('delete'); >@@ -99,13 +98,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 >+$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->multi_param('delete_guarantor'); >+foreach my $id ( @delete_guarantor ) { >+ my $r = Koha::Patron::Relationships->find( $id ); >+ $r->delete() if $r; >+} >+ > ## Deal with debarments > $template->param( > debarments => scalar GetDebarments( { borrowernumber => $borrowernumber } ) ); >@@ -137,14 +148,14 @@ $template->param("uppercasesurnames" => C4::Context->preference('uppercasesurnam > 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 ); >@@ -246,26 +257,6 @@ if ( ( $op eq 'insert' ) and !$nodouble ) { > } > } > >- #recover all data from guarantor address phone ,fax... >-if ( $guarantorid ) { >- if (my $guarantor = Koha::Patrons->find( $guarantorid )) { >- my $guarantordata = $guarantor->unblessed; >- $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')); >@@ -423,6 +414,8 @@ 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); >+ $patron = Koha::Patrons->find( $borrowernumber ); >+ add_guarantors( $patron, $input ); > $newdata{'borrowernumber'} = $borrowernumber; > > # If 'AutoEmailOpacUser' syspref is on, email user their account details from the 'notice' that matches the user's branchcode. >@@ -520,6 +513,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( $patron, $input ); > if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) { > C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes); > } >@@ -627,11 +621,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' ); >@@ -656,24 +649,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 >@@ -749,7 +745,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 >@@ -763,17 +759,12 @@ $template->param( > check_member => $check_member,#to know if the borrower already exist(=>1) or not (=>0) > "op$op" => 1); > >-$guarantorid = $borrower_data->{'guarantorid'} || $guarantorid; >-my $guarantor = $guarantorid ? Koha::Patrons->find( $guarantorid ) : undef; > $template->param( > patron => $patron, # Used by address include templates now > nodouble => $nodouble, > borrowernumber => $borrowernumber, #register number >- guarantor => $guarantor, >- guarantorid => $guarantorid, > relshiploop => \@relshipdata, > btitle=> $default_borrowertitle, >- guarantorinfo => $guarantorinfo, > flagloop => \@flagdata, > category_type =>$category_type, > modify => $modify, >@@ -901,6 +892,28 @@ sub patron_attributes_form { > > } > >+sub add_guarantors { >+ my ( $patron, $input ) = @_; >+ >+ my @new_guarantor_id = $input->multi_param('new_guarantor_id'); >+ my @new_guarantor_relationship = $input->multi_param('new_guarantor_relationship'); >+ >+ for ( my $i = 0 ; $i < scalar @new_guarantor_id; $i++ ) { >+ my $guarantor_id = $new_guarantor_id[$i]; >+ my $relationship = $new_guarantor_relationship[$i]; >+ >+ next unless $guarantor_id; >+ >+ $patron->add_guarantor( >+ { >+ guarantee_id => $patron->id, >+ guarantor_id => $guarantor_id, >+ relationship => $relationship, >+ } >+ ); >+ } >+} >+ > # Local Variables: > # tab-width: 8 > # End: >diff --git a/members/moremember.pl b/members/moremember.pl >index dbe9896377..6157069a7d 100755 >--- a/members/moremember.pl >+++ b/members/moremember.pl >@@ -172,22 +172,20 @@ if ( $patron->is_child ) { > } > > 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') >diff --git a/members/update-child.pl b/members/update-child.pl >index cc942e2704..1546691cd7 100755 >--- a/members/update-child.pl >+++ b/members/update-child.pl >@@ -34,6 +34,7 @@ use C4::Output; > use C4::Members; > use Koha::Patrons; > 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'); > > my $logged_in_user = Koha::Patrons->find( $loggedinuser ) or die "Not logged in"; >@@ -71,11 +72,12 @@ if ( $op eq 'multi' ) { > ); > output_html_with_http_headers $input, $cookie, $template->output; > } >- > elsif ( $op eq 'update' ) { > my $patron = Koha::Patrons->find( $borrowernumber ); > output_and_exit_if_error( $input, $cookie, $template, { module => 'members', logged_in_user => $logged_in_user, current_patron => $patron } ); > >+ $_->delete() for $patron->guarantor_relationships(); >+ > my $member = $patron->unblessed; > $member->{'guarantorid'} = 0; > $member->{'categorycode'} = $catcode; >@@ -85,14 +87,17 @@ elsif ( $op eq 'update' ) { > delete $member->{password}; > ModMember(%$member); > >- 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 ba90ad0ccd..6af24b65fd 100755 >--- a/misc/cronjobs/j2a.pl >+++ b/misc/cronjobs/j2a.pl >@@ -95,6 +95,7 @@ C<juv2adult.pl> - Suggests that you read this help. :) > C<juv2adult.pl> -b=<branchcode> -f=<categorycode> -t=<categorycode> - Processes a single branch, and updates the patron categories from fromcat to tocat. > > C<juv2adult.pl> -f=<categorycode> -t=<categorycode> -v -n - Processes all branches, shows all messages, and reports the patrons who would be affected. Takes no action on the database. >+ > =cut > > # These variables are set by command line options. >@@ -163,12 +164,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 +178,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 +210,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 +218,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 +300,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 9d3bed837e..ab833c1cd7 100755 >--- a/opac/opac-memberentry.pl >+++ b/opac/opac-memberentry.pl >@@ -299,7 +299,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({ > session_id => scalar $cgi->cookie('CGISESSID'), >@@ -320,7 +319,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 78bd30b319..ad4467bccb 100755 >--- a/opac/opac-user.pl >+++ b/opac/opac-user.pl >@@ -40,6 +40,7 @@ use Koha::Holds; > use Koha::Database; > use Koha::ItemTypes; > use Koha::Patron::Attribute::Types; >+use Koha::Patrons; > use Koha::Patron::Messages; > use Koha::Patron::Discharge; > use Koha::Patrons; >@@ -76,6 +77,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; >@@ -338,14 +341,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 81b3f80931..4330e16af0 100755 >--- a/t/Patron.t >+++ b/t/Patron.t >@@ -95,12 +95,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', >@@ -125,7 +120,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' ); >@@ -166,12 +161,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' ); >@@ -195,7 +185,7 @@ subtest 'Accessor tests' => sub { > > # patron Set tests > subtest 'Set tests' => sub { >- plan tests => 65; >+ plan tests => 60; > > $patron->set( > { >@@ -239,12 +229,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', >@@ -307,12 +292,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/NoIssuesChargeGuarantees.t b/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t >index 971208f494..96a5c9bff8 100644 >--- a/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t >+++ b/t/db_dependent/Circulation/NoIssuesChargeGuarantees.t >@@ -26,6 +26,7 @@ use C4::Accounts qw( manualinvoice ); > use C4::Circulation qw( CanBookBeIssued ); > use Koha::Account::Lines; > use Koha::Account::Offsets; >+use Koha::Patron::Relationship; > > my $schema = Koha::Database->new->schema; > $schema->storage->txn_begin; >@@ -52,12 +53,24 @@ my $patron = $builder->build_object( > } > } > ); >-my $guarantee = $builder->build( >+ >+my $guarantee = $builder->build_object( > { >- source => 'Borrower', >- value => { >+ class => 'Koha::Patrons', >+ value => { >+ patron_category => $patron_category->{categorycode}, > guarantorid => $patron->borrowernumber, >- categorycode => $patron_category->{categorycode}, >+ } >+ } >+); >+ >+my $r = $builder->build_object( >+ { >+ class => 'Koha::Patron::Relationships', >+ value => { >+ guarantor_id => $patron->id, >+ guarantee_id => $guarantee->id, >+ relationship => 'parent', > } > } > ); >@@ -68,11 +81,11 @@ t::lib::Mocks::mock_preference( 'AllowFineOverride', '' ); > my ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $item->{barcode} ); > is( $issuingimpossible->{DEBT_GUARANTEES}, undef, "Patron can check out item" ); > >-manualinvoice( $guarantee->{borrowernumber}, undef, undef, 'L', 10.00 ); >+manualinvoice( $guarantee->id, undef, undef, 'L', 10.00 ); > ( $issuingimpossible, $needsconfirmation ) = CanBookBeIssued( $patron, $item->{barcode} ); > is( $issuingimpossible->{DEBT_GUARANTEES} + 0, '10.00' + 0, "Patron cannot check out item due to debt for guarantee" ); > >-my $accountline = Koha::Account::Lines->search({ borrowernumber => $guarantee->{borrowernumber} })->next(); >+my $accountline = Koha::Account::Lines->search({ borrowernumber => $guarantee->id })->next(); > is( $accountline->amountoutstanding, "10.000000", "Found 10.00 amount outstanding" ); > is( $accountline->accounttype, "L", "Account type is L" ); > >diff --git a/t/db_dependent/Items.t b/t/db_dependent/Items.t >index ef098734c9..e5077fbd39 100755 >--- a/t/db_dependent/Items.t >+++ b/t/db_dependent/Items.t >@@ -507,7 +507,7 @@ subtest 'SearchItems test' => sub { > > subtest 'Koha::Item(s) tests' => sub { > >- plan tests => 5; >+ plan tests => 7; > > $schema->storage->txn_begin(); > >@@ -546,6 +546,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 bb6e2bcf98..03e4a2bc30 100644 >--- a/t/db_dependent/Koha/Patrons.t >+++ b/t/db_dependent/Koha/Patrons.t >@@ -35,6 +35,7 @@ use Koha::Holds; > use Koha::Patron; > use Koha::Patrons; > use Koha::Patron::Categories; >+use Koha::Patron::Relationship; > use Koha::Database; > use Koha::DateUtils; > use Koha::Virtualshelves; >@@ -85,23 +86,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 { >@@ -115,15 +118,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 1f9de78f2f..d8c06b9f4d 100755 >--- a/t/db_dependent/Members.t >+++ b/t/db_dependent/Members.t >@@ -27,6 +27,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; >@@ -40,9 +41,6 @@ $schema->storage->txn_begin; > my $builder = t::lib::TestBuilder->new; > my $dbh = C4::Context->dbh; > >-# 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', > }); >@@ -228,7 +226,6 @@ my $borrower1 = $builder->build({ > categorycode=>'STAFFER', > branchcode => $library3->{branchcode}, > dateexpiry => '2015-01-01', >- guarantorid=> undef, > }, > }); > my $bor1inlist = $borrower1->{borrowernumber}; >@@ -238,7 +235,6 @@ my $borrower2 = $builder->build({ > categorycode=>'STAFFER', > branchcode => $library3->{branchcode}, > dateexpiry => '2015-01-01', >- guarantorid=> undef, > }, > }); > >@@ -248,7 +244,6 @@ my $guarantee = $builder->build({ > categorycode=>'KIDclamp', > branchcode => $library3->{branchcode}, > dateexpiry => '2015-01-01', >- guarantorid=> undef, # will be filled later > }, > }); > >@@ -283,7 +278,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'); >@@ -293,7 +288,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', >@@ -321,9 +317,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 0000000000..5bc5b2308b >--- /dev/null >+++ b/t/db_dependent/Patron/Relationships.t >@@ -0,0 +1,167 @@ >+#!/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 <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use Test::More tests => 59; >+ >+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(); >+ >+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, 2, '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' ); >+ >+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 bba512f5f8..52b9d3aa4c 100755 >--- a/tools/import_borrowers.pl >+++ b/tools/import_borrowers.pl >@@ -62,6 +62,7 @@ my $extended = C4::Context->preference('ExtendedPatronAttributes'); > > my @columnkeys = map { $_ ne 'borrowernumber' ? $_ : () } Koha::Patrons->columns(); > push( @columnkeys, 'patron_attributes' ) if $extended; >+push( @columnkeys, qw( relationship guarantor_id guarantor_firstname guarantor_surname ) ); > > my $input = CGI->new(); > >-- >2.11.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 14570
:
52400
|
52401
|
52402
|
52403
|
52406
|
52407
|
58146
|
58147
|
58159
|
58202
|
58391
|
58399
|
58412
|
58688
|
58689
|
58739
|
58762
|
58763
|
58764
|
58834
|
58835
|
58836
|
58837
|
58838
|
58839
|
58949
|
58950
|
58951
|
58952
|
58953
|
58954
|
58972
|
58973
|
58974
|
58975
|
58976
|
58977
|
58978
|
58979
|
58980
|
62450
|
62451
|
62452
|
64124
|
64125
|
64126
|
71160
|
71161
|
71162
|
71163
|
73283
|
73284
|
73583
|
73584
|
74950
|
74951
|
74952
|
74953
|
74954
|
74976
|
74977
|
74978
|
74979
|
77029
|
77030
|
77031
|
77032
|
77033
|
77034
|
77040
|
77041
|
77042
|
77043
|
77044
|
77045
|
77046
|
77047
|
77048
|
77049
|
77067
|
77068
|
77069
|
77070
|
77071
|
77072
|
77073
|
77074
|
77075
|
77076
|
77077
|
77078
|
77290
|
77291
|
77346
|
77347
|
77348
|
80842
|
80849
|
81932
|
81933
|
85411
|
85412
|
85431
|
89889
|
89890
|
89891
|
89892
|
89909
|
89910
|
89911
|
89912
|
89921
|
89922
|
89929
|
90048
|
91231
|
91439
|
91440
|
91441
|
91442
|
91443
|
91444
|
91445
|
91694
|
91695
|
91696
|
91697
|
91698
|
91699
|
91700
|
92157
|
92158
|
92161
|
92162
|
92163
|
92180
|
92181
|
92182
|
92183
|
92232
|
92233
|
92234
|
92235
|
92277
|
92278
|
92279
|
92280
|
92281
|
92282
|
92283
|
92284
|
92285
|
92286
|
92287
|
92288
|
92289
|
92290
|
92291
|
92292
|
92298
|
92299
|
92300
|
92301
|
92302
|
92303
|
92304
|
92305
|
92306
|
92307
|
92308
|
92309
|
92310
|
92311
|
92312
|
92313
|
92314
|
92315
|
92316
|
92317
|
92318
|
92319
|
92320
|
92321
|
92322
|
92323
|
92324
|
92325
|
92346
|
92347
|
92348
|
92349
|
92350