Bug 26265: (QA follow-up) Remove g option from regex, add few dirs
[koha-equinox.git] / Koha / Patron.pm
index 27e552a..5436ccc 100644 (file)
@@ -5,29 +5,30 @@ package Koha::Patron;
 #
 # 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 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.
+# 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.
+# 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 Carp;
 use List::MoreUtils qw( any uniq );
 use JSON qw( to_json );
-use Text::Unaccent qw( unac_string );
+use Unicode::Normalize;
 
 use C4::Context;
 use C4::Log;
 use Koha::Account;
+use Koha::ArticleRequests;
 use Koha::AuthUtils;
 use Koha::Checkouts;
 use Koha::Club::Enrollments;
@@ -41,6 +42,7 @@ use Koha::Patron::Categories;
 use Koha::Patron::HouseboundProfile;
 use Koha::Patron::HouseboundRole;
 use Koha::Patron::Images;
+use Koha::Patron::Modifications;
 use Koha::Patron::Relationships;
 use Koha::Patrons;
 use Koha::Plugins;
@@ -199,6 +201,10 @@ sub store {
             $self->surname( uc($self->surname) )
                 if C4::Context->preference("uppercasesurnames");
 
+            $self->relationship(undef) # We do not want to store an empty string in this field
+              if defined $self->relationship
+                     and $self->relationship eq "";
+
             unless ( $self->in_storage ) {    #AddMember
 
                 # Generate a valid userid/login if needed
@@ -225,10 +231,7 @@ sub store {
                 $self->privacy($default_privacy);
 
                 # Call any check_password plugins if password is passed
-                if (   C4::Context->preference('UseKohaPlugins')
-                    && C4::Context->config("enable_plugins")
-                    && $self->password )
-                {
+                if ( C4::Context->config("enable_plugins") && $self->password ) {
                     my @plugins = Koha::Plugins->new()->GetPlugins({
                         method => 'check_password',
                     });
@@ -381,6 +384,10 @@ sub delete {
             # FIXME Could be $patron->get_lists
             $_->delete for Koha::Virtualshelves->search( { owner => $self->borrowernumber } );
 
+            # We cannot have a FK on borrower_modifications.borrowernumber, the table is also used
+            # for patron selfreg
+            $_->delete for Koha::Patron::Modifications->search( { borrowernumber => $self->borrowernumber } );
+
             $self->SUPER::delete;
 
             logaction( "MEMBERS", "DELETE", $self->borrowernumber, "" ) if C4::Context->preference("BorrowersLog");
@@ -410,7 +417,7 @@ sub category {
 sub image {
     my ( $self ) = @_;
 
-    return scalar Koha::Patron::Images->find( $self->borrowernumber );
+    return Koha::Patron::Images->find( $self->borrowernumber );
 }
 
 =head3 library
@@ -424,6 +431,19 @@ sub library {
     return Koha::Library->_new_from_dbic($self->_result->branchcode);
 }
 
+=head3 sms_provider
+
+Returns a Koha::SMS::Provider object representing the patron's SMS provider.
+
+=cut
+
+sub sms_provider {
+    my ( $self ) = @_;
+    my $sms_provider_rs = $self->_result->sms_provider;
+    return unless $sms_provider_rs;
+    return Koha::SMS::Provider->_new_from_dbic($sms_provider_rs);
+}
+
 =head3 guarantor_relationships
 
 Returns Koha::Patron::Relationships object for this patron's guarantors
@@ -744,7 +764,7 @@ sub set_password {
         }
     }
 
-    if ( C4::Context->preference('UseKohaPlugins') && C4::Context->config("enable_plugins") ) {
+    if ( C4::Context->config("enable_plugins") ) {
         # Call any check_password plugins
         my @plugins = Koha::Plugins->new()->GetPlugins({
             method => 'check_password',
@@ -1326,6 +1346,14 @@ sub libraries_where_can_see_patrons {
     return @restricted_branchcodes;
 }
 
+=head3 has_permission
+
+my $permission = $patron->has_permission($required);
+
+See C4::Auth::haspermission for details of syntax for $required
+
+=cut
+
 sub has_permission {
     my ( $self, $flagsrequired ) = @_;
     return unless $self->userid;
@@ -1415,30 +1443,61 @@ sub generate_userid {
       $firstname =~ s/[[:digit:][:space:][:blank:][:punct:][:cntrl:]]//g;
       $surname =~ s/[[:digit:][:space:][:blank:][:punct:][:cntrl:]]//g;
       my $userid = lc(($firstname)? "$firstname.$surname" : $surname);
-      $userid = unac_string('utf-8',$userid);
+      $userid = NFKD( $userid );
+      $userid =~ s/\p{NonspacingMark}//g;
       $userid .= $offset unless $offset == 0;
       $self->userid( $userid );
       $offset++;
      } while (! $self->has_valid_userid );
 
      return $self;
-
 }
 
-=head3 attributes
+=head3 add_extended_attribute
 
-my $attributes = $patron->attributes
+=cut
+
+sub add_extended_attribute {
+    my ($self, $attribute) = @_;
+    $attribute->{borrowernumber} = $self->borrowernumber;
+    return Koha::Patron::Attribute->new($attribute)->store;
+}
+
+=head3 extended_attributes
 
 Return object of Koha::Patron::Attributes type with all attributes set for this patron
 
+Or setter FIXME
+
 =cut
 
-sub attributes {
-    my ( $self ) = @_;
-    return Koha::Patron::Attributes->search({
-        borrowernumber => $self->borrowernumber,
-        branchcode     => $self->branchcode,
-    });
+sub extended_attributes {
+    my ( $self, $attributes ) = @_;
+    if ($attributes) {    # setter
+        my $schema = $self->_result->result_source->schema;
+        $schema->txn_do(
+            sub {
+                # Remove the existing one
+                $self->extended_attributes->filter_by_branch_limitations->delete;
+
+                # Insert the new ones
+                for my $attribute (@$attributes) {
+                    eval {
+                        $self->_result->create_related('borrower_attributes', $attribute);
+                    };
+                    # FIXME We should:
+                    # 1 - Raise an exception
+                    # 2 - Execute in a transaction and don't save
+                    #  or Insert anyway but display a message on the UI
+                    warn $@ if $@;
+                }
+            }
+        );
+    }
+
+    my $rs = $self->_result->borrower_attributes;
+    # We call search to use the filters in Koha::Patron::Attributes->search
+    return Koha::Patron::Attributes->_new_from_dbic($rs)->search;
 }
 
 =head3 lock
@@ -1544,6 +1603,30 @@ sub add_guarantor {
     )->store();
 }
 
+=head3 get_extended_attribute
+
+my $attribute_value = $patron->get_extended_attribute( $code );
+
+Return the attribute for the code passed in parameter.
+
+It not exist it returns undef
+
+Note that this will not work for repeatable attribute types.
+
+Maybe you certainly not want to use this method, it is actually only used for SHOW_BARCODE
+(which should be a real patron's attribute (not extended)
+
+=cut
+
+sub get_extended_attribute {
+    my ( $self, $code, $value ) = @_;
+    my $rs = $self->_result->borrower_attributes;
+    return unless $rs;
+    my $attribute = $rs->search({ code => $code, ( $value ? ( attribute => $value ) : () ) });
+    return unless $attribute->count;
+    return $attribute->next;
+}
+
 =head3 to_api
 
     my $json = $patron->to_api;
@@ -1554,9 +1637,9 @@ suitable for API output.
 =cut
 
 sub to_api {
-    my ( $self ) = @_;
+    my ( $self, $params ) = @_;
 
-    my $json_patron = $self->SUPER::to_api;
+    my $json_patron = $self->SUPER::to_api( $params );
 
     $json_patron->{restricted} = ( $self->is_debarred )
                                     ? Mojo::JSON->true
@@ -1603,6 +1686,7 @@ sub to_api_mapping {
         smsalertnumber      => 'sms_number',
         sort1               => 'statistics_1',
         sort2               => 'statistics_2',
+        autorenew_checkouts => 'autorenew_checkouts',
         streetnumber        => 'street_number',
         streettype          => 'street_type',
         zipcode             => 'postal_code',