View | Details | Raw Unified | Return to bug 33940
Collapse All | Expand All

(-)a/C4/Members.pm (-61 lines)
Lines 52-59 BEGIN { Link Here
52
      IssueSlip
52
      IssueSlip
53
53
54
      checkuserpassword
54
      checkuserpassword
55
      get_cardnumber_length
56
      checkcardnumber
57
55
58
      DeleteUnverifiedOpacRegistrations
56
      DeleteUnverifiedOpacRegistrations
59
      DeleteExpiredOpacRegistrations
57
      DeleteExpiredOpacRegistrations
Lines 291-355 sub GetAllIssues { Link Here
291
    return $sth->fetchall_arrayref( {} );
289
    return $sth->fetchall_arrayref( {} );
292
}
290
}
293
291
294
sub checkcardnumber {
295
    my ( $cardnumber, $borrowernumber ) = @_;
296
297
    # If cardnumber is null, we assume they're allowed.
298
    return 0 unless defined $cardnumber;
299
300
    my $dbh = C4::Context->dbh;
301
    my $query = "SELECT * FROM borrowers WHERE cardnumber=?";
302
    $query .= " AND borrowernumber <> ?" if ($borrowernumber);
303
    my $sth = $dbh->prepare($query);
304
    $sth->execute(
305
        $cardnumber,
306
        ( $borrowernumber ? $borrowernumber : () )
307
    );
308
309
    return 1 if $sth->fetchrow_hashref;
310
311
    my ( $min_length, $max_length ) = get_cardnumber_length();
312
    return 2
313
        if length $cardnumber > $max_length
314
        or length $cardnumber < $min_length;
315
316
    return 0;
317
}
318
319
=head2 get_cardnumber_length
320
321
    my ($min, $max) = C4::Members::get_cardnumber_length()
322
323
Returns the minimum and maximum length for patron cardnumbers as
324
determined by the CardnumberLength system preference, the
325
BorrowerMandatoryField system preference, and the width of the
326
database column.
327
328
=cut
329
330
sub get_cardnumber_length {
331
    my $borrower = Koha::Database->new->schema->resultset('Borrower');
332
    my $field_size = $borrower->result_source->column_info('cardnumber')->{size};
333
    my ( $min, $max ) = ( 0, $field_size ); # borrowers.cardnumber is a nullable varchar(20)
334
    $min = 1 if C4::Context->preference('BorrowerMandatoryField') =~ /cardnumber/;
335
    if ( my $cardnumber_length = C4::Context->preference('CardnumberLength') ) {
336
        # Is integer and length match
337
        if ( $cardnumber_length =~ m|^\d+$| ) {
338
            $min = $max = $cardnumber_length
339
                if $cardnumber_length >= $min
340
                    and $cardnumber_length <= $max;
341
        }
342
        # Else assuming it is a range
343
        elsif ( $cardnumber_length =~ m|(\d*),(\d*)| ) {
344
            $min = $1 if $1 and $min < $1;
345
            $max = $2 if $2 and $max > $2;
346
        }
347
348
    }
349
    $min = $max if $min > $max;
350
    return ( $min, $max );
351
}
352
353
=head2 GetBorrowersToExpunge
292
=head2 GetBorrowersToExpunge
354
293
355
  $borrowers = &GetBorrowersToExpunge(
294
  $borrowers = &GetBorrowersToExpunge(
(-)a/Koha/Patrons/Import.pm (-2 / +3 lines)
Lines 23-35 use Text::CSV; Link Here
23
use Encode qw( decode_utf8 );
23
use Encode qw( decode_utf8 );
24
use Try::Tiny qw( catch try );
24
use Try::Tiny qw( catch try );
25
25
26
use C4::Members qw( checkcardnumber );
27
use C4::Letters qw( GetPreparedLetter EnqueueLetter );
26
use C4::Letters qw( GetPreparedLetter EnqueueLetter );
28
27
29
use Koha::Libraries;
28
use Koha::Libraries;
30
use Koha::Patrons;
29
use Koha::Patrons;
31
use Koha::Patron::Categories;
30
use Koha::Patron::Categories;
32
use Koha::Patron::Debarments qw( AddDebarment );
31
use Koha::Patron::Debarments qw( AddDebarment );
32
use Koha::Policy::Patrons::Cardnumber;
33
use Koha::DateUtils qw( dt_from_string output_pref );
33
use Koha::DateUtils qw( dt_from_string output_pref );
34
34
35
=head1 NAME
35
=head1 NAME
Lines 212-218 sub import_patrons { Link Here
212
            $is_new = 1;
212
            $is_new = 1;
213
        }
213
        }
214
214
215
        if ( C4::Members::checkcardnumber( $borrower{cardnumber}, $borrowernumber ) ) {
215
        my $is_valid = Koha::Policy::Patrons::Cardnumber->is_valid($borrower{cardnumber}, $patron);
216
        unless ( $is_valid ) {
216
            push @errors,
217
            push @errors,
217
              {
218
              {
218
                invalid_cardnumber => 1,
219
                invalid_cardnumber => 1,
(-)a/Koha/Policy/Patrons/Cardnumber.pm (+110 lines)
Line 0 Link Here
1
package Koha::Policy::Patrons::Cardnumber;
2
3
# Copyright 2023 Koha Development team
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use C4::Context;
23
24
use Koha::Patrons;
25
use Koha::Result::Boolean;
26
27
=head1 NAME
28
29
Koha::Policy::Patrons::Cardnumber - module to deal with cardnumbers policy
30
31
=head1 API
32
33
=head2 Class Methods
34
35
=head3 new
36
37
=cut
38
39
sub new {
40
    return bless {}, shift;
41
}
42
43
=head3 is_valid
44
45
    my $is_valid = Koha::Policy::Patrons::Cardnumber->is_valid( $cardnumber, [$patron] );
46
47
Returns whether a cardnumber is valid of not for a given I<Koha::Patron> object.
48
49
=cut
50
51
sub is_valid {
52
    my ( $class, $cardnumber, $patron ) = @_;
53
54
    return Koha::Result::Boolean->new(0)->add_message( { message => "is_empty" } )
55
        unless defined $cardnumber;
56
57
    return Koha::Result::Boolean->new(0)->add_message( { message => "already_exists" } )
58
        if Koha::Patrons->search(
59
        {
60
            cardnumber => $cardnumber,
61
            ( $patron ? ( borrowernumber => { '!=' => $patron->borrowernumber } ) : () )
62
        }
63
    )->count;
64
65
    my ( $min_length, $max_length ) = $class->get_valid_length();
66
    return Koha::Result::Boolean->new(0)->add_message( { message => "invalid_length" } )
67
        if length $cardnumber > $max_length
68
        or length $cardnumber < $min_length;
69
70
    return Koha::Result::Boolean->new(1);
71
}
72
73
=head2 get_valid_length
74
75
    my ($min, $max) = Koha::Policy::Patrons::Cardnumber::get_valid_length();
76
77
Returns the minimum and maximum length for patron cardnumbers as
78
determined by the CardnumberLength system preference, the
79
BorrowerMandatoryField system preference, and the width of the
80
database column.
81
82
=cut
83
84
sub get_valid_length {
85
    my ($class)    = @_;
86
    my $borrower   = Koha::Database->new->schema->resultset('Borrower');
87
    my $field_size = $borrower->result_source->column_info('cardnumber')->{size};
88
    my ( $min, $max ) = ( 0, $field_size );    # borrowers.cardnumber is a nullable varchar(20)
89
    $min = 1 if C4::Context->preference('BorrowerMandatoryField') =~ /cardnumber/;
90
    if ( my $cardnumber_length = C4::Context->preference('CardnumberLength') ) {
91
92
        # Is integer and length match
93
        if ( $cardnumber_length =~ m|^\d+$| ) {
94
            $min = $max = $cardnumber_length
95
                if $cardnumber_length >= $min
96
                and $cardnumber_length <= $max;
97
        }
98
99
        # Else assuming it is a range
100
        elsif ( $cardnumber_length =~ m|(\d*),(\d*)| ) {
101
            $min = $1 if $1 and $min < $1;
102
            $max = $2 if $2 and $max > $2;
103
        }
104
105
    }
106
    $min = $max if $min > $max;
107
    return ( $min, $max );
108
}
109
110
1;
(-)a/installer/onboarding.pl (-7 / +10 lines)
Lines 22-33 use C4::Context; Link Here
22
use C4::InstallAuth qw( checkauth get_template_and_user );
22
use C4::InstallAuth qw( checkauth get_template_and_user );
23
use CGI qw ( -utf8 );
23
use CGI qw ( -utf8 );
24
use C4::Output qw( output_html_with_http_headers );
24
use C4::Output qw( output_html_with_http_headers );
25
use C4::Members qw( checkcardnumber );
26
use Koha::Patrons;
25
use Koha::Patrons;
27
use Koha::Libraries;
26
use Koha::Libraries;
28
use Koha::Database;
27
use Koha::Database;
29
use Koha::Patrons;
28
use Koha::Patrons;
30
use Koha::Patron::Categories;
29
use Koha::Patron::Categories;
30
use Koha::Policy::Patrons::Cardnumber;
31
use Koha::ItemTypes;
31
use Koha::ItemTypes;
32
use Koha::CirculationRules;
32
use Koha::CirculationRules;
33
33
Lines 141-152 if ( $step == 3 ) { Link Here
141
            $patron_category );
141
            $patron_category );
142
142
143
143
144
        if ( my $error_code = checkcardnumber($cardnumber) ) {
144
        my $is_cardnumber_valid = Koha::Policy::Patrons::Cardnumber->is_valid($cardnumber);
145
            if ( $error_code == 1 ) {
145
        unless ( $is_cardnumber_valid ) {
146
                push @messages, { code => 'ERROR_cardnumber_already_exists' };
146
            for my $message ( @{ $is_cardnumber_valid->messages } ) {
147
            }
147
                if ( $message eq 'already_exists' ) {
148
            elsif ( $error_code == 2 ) {
148
                    push @messages, { code => 'ERROR_cardnumber_already_exists' };
149
                push @messages, { code => 'ERROR_cardnumber_length' };
149
                }
150
                elsif ( $message eq 'invalid_length' ) {
151
                    push @messages, { code => 'ERROR_cardnumber_length' };
152
                }
150
            }
153
            }
151
        }
154
        }
152
        elsif ( $firstpassword ne $secondpassword ) {
155
        elsif ( $firstpassword ne $secondpassword ) {
(-)a/members/memberentry.pl (-8 / +11 lines)
Lines 29-35 use CGI qw ( -utf8 ); Link Here
29
use C4::Auth qw( get_template_and_user haspermission );
29
use C4::Auth qw( get_template_and_user haspermission );
30
use C4::Context;
30
use C4::Context;
31
use C4::Output qw( output_and_exit output_and_exit_if_error output_html_with_http_headers );
31
use C4::Output qw( output_and_exit output_and_exit_if_error output_html_with_http_headers );
32
use C4::Members qw( checkcardnumber get_cardnumber_length );
33
use C4::Koha qw( GetAuthorisedValues );
32
use C4::Koha qw( GetAuthorisedValues );
34
use C4::Letters qw( GetPreparedLetter EnqueueLetter SendQueuedMessages );
33
use C4::Letters qw( GetPreparedLetter EnqueueLetter SendQueuedMessages );
35
use C4::Form::MessagingPreferences;
34
use C4::Form::MessagingPreferences;
Lines 46-51 use Koha::Patron::Attribute::Types; Link Here
46
use Koha::Patron::Categories;
45
use Koha::Patron::Categories;
47
use Koha::Patron::HouseboundRole;
46
use Koha::Patron::HouseboundRole;
48
use Koha::Patron::HouseboundRoles;
47
use Koha::Patron::HouseboundRoles;
48
use Koha::Policy::Patrons::Cardnumber;
49
use Koha::Plugins;
49
use Koha::Plugins;
50
use Koha::Token;
50
use Koha::Token;
51
use Koha::SMS::Providers;
51
use Koha::SMS::Providers;
Lines 293-304 if ($op eq 'save' || $op eq 'insert'){ Link Here
293
293
294
    $newdata{'cardnumber'} = $new_barcode;
294
    $newdata{'cardnumber'} = $new_barcode;
295
295
296
    if (my $error_code = checkcardnumber( $newdata{cardnumber}, $borrowernumber )){
296
    my $is_valid = Koha::Policy::Patrons::Cardnumber->is_valid($newdata{cardnumber}, $patron );
297
        push @errors, $error_code == 1
297
    unless ($is_valid) {
298
            ? 'ERROR_cardnumber_already_exists'
298
        for my $message ( @{ $is_valid->messages } ) {
299
            : $error_code == 2
299
            if ( $message eq 'already_exists' ) {
300
                ? 'ERROR_cardnumber_length'
300
                push @messages, { code => 'ERROR_cardnumber_already_exists' };
301
                : ()
301
            } elsif ( $message eq 'invalid_length' ) {
302
                push @messages, { code => 'ERROR_cardnumber_length' };
303
            }
304
        }
302
    }
305
    }
303
306
304
    my $dateofbirth;
307
    my $dateofbirth;
Lines 786-792 if(defined($data{'contacttitle'})){ Link Here
786
}
789
}
787
790
788
791
789
my ( $min, $max ) = C4::Members::get_cardnumber_length();
792
my ( $min, $max ) = Koha::Policy::Patrons::Cardnumber->get_valid_length();
790
if ( defined $min ) {
793
if ( defined $min ) {
791
    $template->param(
794
    $template->param(
792
        minlength_cardnumber => $min,
795
        minlength_cardnumber => $min,
(-)a/opac/opac-memberentry.pl (-10 / +15 lines)
Lines 28-34 use C4::Auth qw( get_template_and_user ); Link Here
28
use C4::Output qw( output_html_with_http_headers );
28
use C4::Output qw( output_html_with_http_headers );
29
use C4::Context;
29
use C4::Context;
30
use C4::Letters qw( GetPreparedLetter EnqueueLetter SendQueuedMessages );
30
use C4::Letters qw( GetPreparedLetter EnqueueLetter SendQueuedMessages );
31
use C4::Members qw( checkcardnumber );
32
use C4::Form::MessagingPreferences;
31
use C4::Form::MessagingPreferences;
33
use Koha::AuthUtils;
32
use Koha::AuthUtils;
34
use Koha::Patrons;
33
use Koha::Patrons;
Lines 43-48 use Koha::Patron::Attribute::Types; Link Here
43
use Koha::Patron::Attributes;
42
use Koha::Patron::Attributes;
44
use Koha::Patron::Images;
43
use Koha::Patron::Images;
45
use Koha::Patron::Categories;
44
use Koha::Patron::Categories;
45
use Koha::Policy::Patrons::Cardnumber;
46
use Koha::Token;
46
use Koha::Token;
47
use Koha::AuthorisedValues;
47
use Koha::AuthorisedValues;
48
my $cgi = CGI->new;
48
my $cgi = CGI->new;
Lines 88-94 if ( $action eq 'create' || $action eq 'new' ) { Link Here
88
}
88
}
89
my $libraries = Koha::Libraries->search($params);
89
my $libraries = Koha::Libraries->search($params);
90
90
91
my ( $min, $max ) = C4::Members::get_cardnumber_length();
91
my ( $min, $max ) = Koha::Policy::Patrons::Cardnumber->get_valid_length();
92
if ( defined $min ) {
92
if ( defined $min ) {
93
     $template->param(
93
     $template->param(
94
         minlength_cardnumber => $min,
94
         minlength_cardnumber => $min,
Lines 133-151 if ( $action eq 'create' ) { Link Here
133
    my @empty_mandatory_fields = (CheckMandatoryFields( \%borrower, $action ), CheckMandatoryAttributes( \%borrower, $attributes ) );
133
    my @empty_mandatory_fields = (CheckMandatoryFields( \%borrower, $action ), CheckMandatoryAttributes( \%borrower, $attributes ) );
134
    my $invalidformfields = CheckForInvalidFields(\%borrower);
134
    my $invalidformfields = CheckForInvalidFields(\%borrower);
135
    delete $borrower{'password2'};
135
    delete $borrower{'password2'};
136
    my $cardnumber_error_code;
136
    my $is_cardnumber_valid;
137
    if ( !grep { $_ eq 'cardnumber' } @empty_mandatory_fields ) {
137
    if ( !grep { $_ eq 'cardnumber' } @empty_mandatory_fields ) {
138
        # No point in checking the cardnumber if it's missing and mandatory, it'll just generate a
138
        # No point in checking the cardnumber if it's missing and mandatory, it'll just generate a
139
        # spurious length warning.
139
        # spurious length warning.
140
        $cardnumber_error_code = checkcardnumber( $borrower{cardnumber}, $borrower{borrowernumber} );
140
        my $patron = Koha::Patrons->find($borrower{borrowernumber});
141
        $is_cardnumber_valid = Koha::Policy::Patrons::Cardnumber($borrower{cardnumber}, $patron);
142
        unless ($is_cardnumber_valid) {
143
            for my $message ( @{ $is_cardnumber_valid->messages } ) {
144
                if ( $message eq 'already_exists' ) {
145
                    $template->param( cardnumber_already_exists => 1 );
146
                } elsif ( $message eq 'invalid_length' ) {
147
                    $template->param( cardnumber_wrong_length => 1 );
148
                }
149
            }
150
        }
141
    }
151
    }
142
152
143
    if ( @empty_mandatory_fields || @$invalidformfields || $cardnumber_error_code || $conflicting_attribute ) {
153
    if ( @empty_mandatory_fields || @$invalidformfields || !$is_cardnumber_valid || $conflicting_attribute ) {
144
        if ( $cardnumber_error_code == 1 ) {
145
            $template->param( cardnumber_already_exists => 1 );
146
        } elsif ( $cardnumber_error_code == 2 ) {
147
            $template->param( cardnumber_wrong_length => 1 );
148
        }
149
154
150
        $template->param(
155
        $template->param(
151
            empty_mandatory_fields => \@empty_mandatory_fields,
156
            empty_mandatory_fields => \@empty_mandatory_fields,
(-)a/t/Members/cardnumber.t (-96 lines)
Lines 1-96 Link Here
1
#!/usr/bin/env perl
2
3
use Modern::Perl;
4
use Module::Load::Conditional qw/check_install/;
5
use Test::More;
6
use Test::MockModule;
7
8
use t::lib::Mocks;
9
10
use_ok('C4::Members', qw( get_cardnumber_length checkcardnumber ));
11
12
BEGIN {
13
    if ( check_install( module => 'Test::DBIx::Class' ) ) {
14
        plan tests => 25;
15
    } else {
16
        plan skip_all => "Need Test::DBIx::Class"
17
    }
18
}
19
20
use Test::DBIx::Class;
21
22
my $db = Test::MockModule->new('Koha::Database');
23
$db->mock( _new_schema => sub { return Schema(); } );
24
25
my $dbh = C4::Context->dbh;
26
my $rs = [];
27
28
my $borrower = Koha::Schema->resultset('Borrower');
29
my $cardnumber_size = $borrower->result_source->column_info('cardnumber')->{size};
30
31
t::lib::Mocks::mock_preference('BorrowerMandatoryField', '');
32
my $pref = "10";
33
t::lib::Mocks::mock_preference('CardnumberLength', $pref);
34
is_deeply( [ C4::Members::get_cardnumber_length() ], [ 10, 10 ], '10 => min=10 and max=10');
35
$dbh->{mock_add_resultset} = $rs;
36
is( C4::Members::checkcardnumber( q{123456789} ), 2, "123456789 is shorter than $pref");
37
$dbh->{mock_add_resultset} = $rs;
38
is( C4::Members::checkcardnumber( q{1234567890123456} ), 2, "1234567890123456 is longer than $pref");
39
$dbh->{mock_add_resultset} = $rs;
40
is( C4::Members::checkcardnumber( q{1234567890} ), 0, "1234567890 is equal to $pref");
41
42
$pref = q|10,10|; # Same as before !
43
t::lib::Mocks::mock_preference('CardnumberLength', $pref);
44
is_deeply( [ C4::Members::get_cardnumber_length() ], [ 10, 10 ], '10,10 => min=10 and max=10');
45
$dbh->{mock_add_resultset} = $rs;
46
is( C4::Members::checkcardnumber( q{123456789} ), 2, "123456789 is shorter than $pref");
47
$dbh->{mock_add_resultset} = $rs;
48
is( C4::Members::checkcardnumber( q{1234567890123456} ), 2, "1234567890123456 is longer than $pref");
49
$dbh->{mock_add_resultset} = $rs;
50
is( C4::Members::checkcardnumber( q{1234567890} ), 0, "1234567890 is equal to $pref");
51
52
$pref = q|8,10|; # between 8 and 10 chars
53
t::lib::Mocks::mock_preference('CardnumberLength', $pref);
54
is_deeply( [ C4::Members::get_cardnumber_length() ], [ 8, 10 ], '8,10 => min=8 and max=10');
55
$dbh->{mock_add_resultset} = $rs;
56
is( C4::Members::checkcardnumber( q{12345678} ), 0, "12345678 matches $pref");
57
$dbh->{mock_add_resultset} = $rs;
58
is( C4::Members::checkcardnumber( q{1234567890123456} ), 2, "1234567890123456 is longer than $pref");
59
$dbh->{mock_add_resultset} = $rs;
60
is( C4::Members::checkcardnumber( q{1234567} ), 2, "1234567 is shorter than $pref");
61
$dbh->{mock_add_resultset} = $rs;
62
is( C4::Members::checkcardnumber( q{1234567890} ), 0, "1234567890 matches $pref");
63
64
$pref = q|8,|; # At least 8 chars
65
t::lib::Mocks::mock_preference('CardnumberLength', $pref);
66
is_deeply( [ C4::Members::get_cardnumber_length() ], [ 8, $cardnumber_size ], "8, => min=8 and max=$cardnumber_size");
67
$dbh->{mock_add_resultset} = $rs;
68
is( C4::Members::checkcardnumber( q{1234567} ), 2, "1234567 is shorter than $pref");
69
$dbh->{mock_add_resultset} = $rs;
70
is( C4::Members::checkcardnumber( q{1234567890123456} ), 0, "1234567890123456 matches $pref");
71
$dbh->{mock_add_resultset} = $rs;
72
is( C4::Members::checkcardnumber( q{1234567890} ), 0, "1234567890 matches $pref");
73
74
$pref = q|,8|; # max 8 chars
75
t::lib::Mocks::mock_preference('CardnumberLength', $pref);
76
is_deeply( [ C4::Members::get_cardnumber_length() ], [ 0, 8 ], ',8 => min=0 and max=8');
77
$dbh->{mock_add_resultset} = $rs;
78
is( C4::Members::checkcardnumber( q{1234567} ), 0, "1234567 matches $pref");
79
$dbh->{mock_add_resultset} = $rs;
80
is( C4::Members::checkcardnumber( q{1234567890123456} ), 2, "1234567890123456 is longer than $pref");
81
$dbh->{mock_add_resultset} = $rs;
82
is( C4::Members::checkcardnumber( q{1234567890} ), 2, "1234567890 is longer than $pref");
83
84
$pref = sprintf(',%d', $cardnumber_size+1);
85
t::lib::Mocks::mock_preference('CardnumberLength', $pref);
86
is_deeply( [ C4::Members::get_cardnumber_length() ], [ 0, $cardnumber_size ],
87
    sprintf(",%d => min=0 and max=%d",$cardnumber_size+1,$cardnumber_size) );
88
$dbh->{mock_add_resultset} = $rs;
89
90
my $generated_cardnumber = sprintf("%s1234567890",q|9|x$cardnumber_size);
91
is( C4::Members::checkcardnumber( $generated_cardnumber ), 2, "$generated_cardnumber is longer than $pref => $cardnumber_size is max!");
92
93
$pref = q|,8|; # max 8 chars
94
t::lib::Mocks::mock_preference('CardnumberLength', $pref);
95
t::lib::Mocks::mock_preference('BorrowerMandatoryField', 'cardnumber');
96
is_deeply( [ C4::Members::get_cardnumber_length() ], [ 1, 8 ], ',8 => min=1 and max=8 if cardnumber is mandatory');
(-)a/t/db_dependent/Koha/Policy/Patrons/Cardnumber.t (+160 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2023 Koha Development team
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::More tests => 3;
23
24
use Koha::Database;
25
use Koha::Policy::Patrons::Cardnumber;
26
use t::lib::Mocks;
27
use t::lib::TestBuilder;
28
29
my $schema  = Koha::Database->new->schema;
30
my $builder = t::lib::TestBuilder->new;
31
32
subtest 'is_valid' => sub {
33
34
    plan tests => 21;
35
36
    $schema->storage->txn_begin;
37
38
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
39
40
    t::lib::Mocks::mock_preference( 'CardnumberLength', '' );
41
42
    my $policy = Koha::Policy::Patrons::Cardnumber->new;
43
44
    my $is_valid = $policy->is_valid( $patron->cardnumber );
45
    ok( !$is_valid, "Cardnumber in use, cannot be reused");
46
47
    $is_valid = $policy->is_valid( $patron->cardnumber, $patron );
48
    ok( $is_valid, "Cardnumber in use but can be used by the same patron");
49
50
    my $tmp_patron = $builder->build_object({ class => 'Koha::Patrons' });
51
    my $available_cardnumber = $tmp_patron->cardnumber;
52
    $tmp_patron->delete;
53
    $is_valid = $policy->is_valid( $available_cardnumber );
54
    ok( $is_valid, "Cardnumber not in use");
55
56
    t::lib::Mocks::mock_preference( 'CardnumberLength', '4' );
57
58
    $is_valid = $policy->is_valid( "12345" );
59
    ok( !$is_valid, "Invalid cardnumber length");
60
61
    $is_valid = $policy->is_valid( "123" );
62
    ok( !$is_valid, "Invalid cardnumber length");
63
64
    my $pref = "10";
65
    t::lib::Mocks::mock_preference('CardnumberLength', $pref);
66
    ok( !$policy->is_valid( q{123456789} ), "123456789 is shorter than $pref");
67
    ok( !$policy->is_valid( q{1234567890123456} ), "1234567890123456 is longer than $pref");
68
    ok( $policy->is_valid( q{1234567890} ), "1234567890 is equal to $pref");
69
70
    $pref = q|10,10|; # Same as before !
71
    t::lib::Mocks::mock_preference('CardnumberLength', $pref);
72
    ok( !$policy->is_valid( q{123456789} ), "123456789 is shorter than $pref");
73
    ok( !$policy->is_valid( q{1234567890123456} ), "1234567890123456 is longer than $pref");
74
    ok( $policy->is_valid( q{1234567890} ), "1234567890 is equal to $pref");
75
76
    $pref = q|8,10|; # between 8 and 10 chars
77
    t::lib::Mocks::mock_preference('CardnumberLength', $pref);
78
    ok( $policy->is_valid( q{12345678} ), "12345678 matches $pref");
79
    ok( !$policy->is_valid( q{1234567890123456} ), "1234567890123456 is longer than $pref");
80
    ok( !$policy->is_valid( q{1234567} ), "1234567 is shorter than $pref");
81
    ok( $policy->is_valid( q{1234567890} ), "1234567890 matches $pref");
82
83
    $pref = q|8,|; # At least 8 chars
84
    t::lib::Mocks::mock_preference('CardnumberLength', $pref);
85
    ok( !$policy->is_valid( q{1234567} ), "1234567 is shorter than $pref");
86
    ok( $policy->is_valid( q{1234567890123456} ), "1234567890123456 matches $pref");
87
    ok( $policy->is_valid( q{1234567890} ), "1234567890 matches $pref");
88
89
    $pref = q|,8|; # max 8 chars
90
    t::lib::Mocks::mock_preference('CardnumberLength', $pref);
91
    ok( $policy->is_valid( q{1234567} ), "1234567 matches $pref");
92
    ok( !$policy->is_valid( q{1234567890123456} ), "1234567890123456 is longer than $pref");
93
    ok( !$policy->is_valid( q{1234567890} ), "1234567890 is longer than $pref");
94
95
    $schema->storage->txn_rollback;
96
};
97
98
subtest 'get_valid_length' => sub {
99
100
    plan tests => 5;
101
102
    $schema->storage->txn_begin;
103
104
    my $policy = Koha::Policy::Patrons::Cardnumber->new;
105
106
    t::lib::Mocks::mock_preference('BorrowerMandatoryField', '');
107
108
    my $pref = "10";
109
    t::lib::Mocks::mock_preference( 'CardnumberLength', $pref );
110
    is_deeply( [ $policy->get_valid_length() ], [ 10, 10 ], '10 => min=10 and max=10' );
111
112
    $pref = q|10,10|;    # Same as before !
113
    t::lib::Mocks::mock_preference( 'CardnumberLength', $pref );
114
    is_deeply( [ $policy->get_valid_length() ], [ 10, 10 ], '10,10 => min=10 and max=10' );
115
116
    $pref = q|8,10|;     # between 8 and 10 chars
117
    t::lib::Mocks::mock_preference( 'CardnumberLength', $pref );
118
    is_deeply( [ $policy->get_valid_length() ], [ 8, 10 ], '8,10 => min=8 and max=10' );
119
120
    $pref = q|,8|;       # max 8 chars
121
    t::lib::Mocks::mock_preference( 'CardnumberLength', $pref );
122
    is_deeply( [ $policy->get_valid_length() ], [ 0, 8 ], ',8 => min=0 and max=8' );
123
124
    $pref = q|,8|; # max 8 chars
125
    t::lib::Mocks::mock_preference('CardnumberLength', $pref);
126
    t::lib::Mocks::mock_preference('BorrowerMandatoryField', 'cardnumber');
127
    is_deeply( [ $policy->get_valid_length() ], [ 1, 8 ], ',8 => min=1 and max=8 if cardnumber is mandatory');
128
129
    $schema->storage->txn_rollback;
130
131
};
132
133
subtest 'compare with DB data size' => sub {
134
135
    plan tests => 3;
136
137
    $schema->storage->txn_begin;
138
139
    my $policy = Koha::Policy::Patrons::Cardnumber->new;
140
    my $borrower        = Koha::Schema->resultset('Borrower');
141
    my $cardnumber_size = $borrower->result_source->column_info('cardnumber')->{size};
142
    t::lib::Mocks::mock_preference('BorrowerMandatoryField', '');
143
144
    my $pref = q|8,|;       # At least 8 chars
145
    t::lib::Mocks::mock_preference( 'CardnumberLength', $pref );
146
    is_deeply( [ $policy->get_valid_length() ], [ 8, $cardnumber_size ], "8, => min=8 and max=$cardnumber_size" );
147
148
    $pref = sprintf( ',%d', $cardnumber_size + 1 );
149
    t::lib::Mocks::mock_preference( 'CardnumberLength', $pref );
150
    is_deeply(
151
        [ $policy->get_valid_length() ], [ 0, $cardnumber_size ],
152
        sprintf( ",%d => min=0 and max=%d", $cardnumber_size + 1, $cardnumber_size )
153
    );
154
155
    my $generated_cardnumber = sprintf("%s1234567890",q|9|x$cardnumber_size);
156
    ok( !$policy->is_valid( $generated_cardnumber ), "$generated_cardnumber is longer than $pref => $cardnumber_size is max!");
157
158
    $schema->storage->txn_rollback;
159
160
};
(-)a/t/db_dependent/Members.t (-22 / +2 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 53;
20
use Test::More tests => 50;
21
use Test::MockModule;
21
use Test::MockModule;
22
use Test::Exception;
22
use Test::Exception;
23
23
Lines 33-39 use t::lib::Mocks; Link Here
33
use t::lib::TestBuilder;
33
use t::lib::TestBuilder;
34
34
35
BEGIN {
35
BEGIN {
36
        use_ok('C4::Members', qw( checkcardnumber GetBorrowersToExpunge DeleteUnverifiedOpacRegistrations DeleteExpiredOpacRegistrations ));
36
        use_ok('C4::Members', qw( GetBorrowersToExpunge DeleteUnverifiedOpacRegistrations DeleteExpiredOpacRegistrations ));
37
}
37
}
38
38
39
my $schema = Koha::Database->schema;
39
my $schema = Koha::Database->schema;
Lines 58-66 my $EMAIL = "Marie\@email.com"; Link Here
58
my $EMAILPRO          = "Marie\@work.com";
58
my $EMAILPRO          = "Marie\@work.com";
59
my $PHONE             = "555-12123";
59
my $PHONE             = "555-12123";
60
60
61
# XXX should be randomised and checked against the database
62
my $IMPOSSIBLE_CARDNUMBER = "XYZZZ999";
63
64
t::lib::Mocks::mock_userenv();
61
t::lib::Mocks::mock_userenv();
65
62
66
# Make a borrower for testing
63
# Make a borrower for testing
Lines 104-125 ok ( $changedmember->{firstname} eq $CHANGED_FIRSTNAME && Link Here
104
     , "Member Changed")
101
     , "Member Changed")
105
  or diag("Mismatching member details: ".Dumper($member, $changedmember));
102
  or diag("Mismatching member details: ".Dumper($member, $changedmember));
106
103
107
t::lib::Mocks::mock_preference( 'CardnumberLength', '' );
108
C4::Context->clear_syspref_cache();
109
110
my $checkcardnum=C4::Members::checkcardnumber($CARDNUMBER, "");
111
is ($checkcardnum, "1", "Card No. in use");
112
113
$checkcardnum=C4::Members::checkcardnumber($IMPOSSIBLE_CARDNUMBER, "");
114
is ($checkcardnum, "0", "Card No. not used");
115
116
t::lib::Mocks::mock_preference( 'CardnumberLength', '4' );
117
C4::Context->clear_syspref_cache();
118
119
$checkcardnum=C4::Members::checkcardnumber($IMPOSSIBLE_CARDNUMBER, "");
120
is ($checkcardnum, "2", "Card number is too long");
121
122
123
# Add a new borrower
104
# Add a new borrower
124
%data = (
105
%data = (
125
    cardnumber   => "123456789",
106
    cardnumber   => "123456789",
126
- 

Return to bug 33940