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

(-)a/C4/Auth_with_ldap.pm (-1 lines)
Lines 22-28 use Carp; Link Here
22
22
23
use C4::Debug;
23
use C4::Debug;
24
use C4::Context;
24
use C4::Context;
25
use C4::Members::Attributes;
26
use C4::Members::Messaging;
25
use C4::Members::Messaging;
27
use C4::Auth qw(checkpw_internal);
26
use C4::Auth qw(checkpw_internal);
28
use Koha::Patrons;
27
use Koha::Patrons;
(-)a/C4/Members/Attributes.pm (-92 lines)
Lines 1-92 Link Here
1
package C4::Members::Attributes;
2
3
# Copyright (C) 2008 LibLime
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 strict;
21
use warnings;
22
23
use Text::CSV;      # Don't be tempted to use Text::CSV::Unicode -- even in binary mode it fails.
24
use C4::Context;
25
26
use Koha::Patron::Attribute::Types;
27
28
use vars qw(@ISA @EXPORT_OK @EXPORT %EXPORT_TAGS);
29
our ($csv, $AttributeTypes);
30
31
BEGIN {
32
    @ISA = qw(Exporter);
33
    @EXPORT_OK = qw(
34
                    extended_attributes_code_value_arrayref
35
                    );
36
    %EXPORT_TAGS = ( all => \@EXPORT_OK );
37
}
38
39
=head1 NAME
40
41
C4::Members::Attributes - manage extend patron attributes
42
43
=head1 SYNOPSIS
44
45
  use C4::Members::Attributes;
46
47
=head1 FUNCTIONS
48
49
=head2 extended_attributes_code_value_arrayref 
50
51
   my $patron_attributes = "homeroom:1150605,grade:01,extradata:foobar";
52
   my $aref = extended_attributes_code_value_arrayref($patron_attributes);
53
54
Takes a comma-delimited CSV-style string argument and returns the kind of data structure that Koha::Patron->extended_attributes wants,
55
namely a reference to array of hashrefs like:
56
 [ { code => 'CODE', attribute => 'value' }, { code => 'CODE2', attribute => 'othervalue' } ... ]
57
58
Caches Text::CSV parser object for efficiency.
59
60
=cut
61
62
sub extended_attributes_code_value_arrayref {
63
    my $string = shift or return;
64
    use Data::Printer colored => 1; warn p $string;
65
    $csv or $csv = Text::CSV->new({binary => 1});  # binary needed for non-ASCII Unicode
66
    my $ok   = $csv->parse($string);  # parse field again to get subfields!
67
    my @list = $csv->fields();
68
    # TODO: error handling (check $ok)
69
    return [
70
        sort {&_sort_by_code($a,$b)}
71
        map { map { my @arr = split /:/, $_, 2; { code => $arr[0], attribute => $arr[1] } } $_ }
72
        @list
73
    ];
74
    # nested map because of split
75
}
76
77
sub _sort_by_code {
78
    my ($x, $y) = @_;
79
    defined ($x->{code}) or return -1;
80
    defined ($y->{code}) or return 1;
81
    return $x->{code} cmp $y->{code} || $x->{value} cmp $y->{value};
82
}
83
84
=head1 AUTHOR
85
86
Koha Development Team <http://koha-community.org/>
87
88
Galen Charlton <galen.charlton@liblime.com>
89
90
=cut
91
92
1;
(-)a/Koha/Patron/Attributes.pm (-6 / +14 lines)
Lines 87-110 sub filter_by_branch_limitations { Link Here
87
    return $self->search( $or, $join );
87
    return $self->search( $or, $join );
88
}
88
}
89
89
90
=head3
91
92
$new_attributes is an arrayref of hashrefs
93
94
=cut
95
90
sub merge_with {
96
sub merge_with {
91
    my ( $self, $new_attributes ) = @_;
97
    my ( $self, $new_attributes ) = @_;
92
98
93
    my @merged = $self->as_list;
99
    my @merged = $self->as_list;
94
    while ( my ( $attr ) = $new_attributes->next ) {
100
    my $attribute_types = { map { $_->code => $_->unblessed } Koha::Patron::Attribute::Types->search };
95
        unless ( $attr->code ) {
101
    for my $attr ( @$new_attributes ) {
102
        unless ( $attr->{code} ) {
96
            warn "Cannot merge element: no 'code' defined";
103
            warn "Cannot merge element: no 'code' defined";
97
            next;
104
            next;
98
        }
105
        }
99
106
107
        my $attribute_type = $attribute_types->{$attr->{code}};
100
        # FIXME Do we need that here or let ->store do the job?
108
        # FIXME Do we need that here or let ->store do the job?
101
        unless ( $attr->type ) {
109
        unless ( $attribute_type ) {
102
            warn "Cannot merge element: unrecognized code = '$attr->code'";
110
            warn "Cannot merge element: unrecognized code = '$attr->{code}'";
103
            next;
111
            next;
104
        }
112
        }
105
        unless ( $attr->type->repeatable ) {
113
        unless ( $attribute_type->{repeatable} ) {
106
            # filter out any existing attributes of the same code
114
            # filter out any existing attributes of the same code
107
            @merged = grep {$attr->code ne $_->code} @merged;
115
            @merged = grep {$attr->{code} ne $_->code} @merged;
108
        }
116
        }
109
117
110
        push @merged, $attr;
118
        push @merged, $attr;
(-)a/Koha/Patrons/Import.pm (-19 / +25 lines)
Lines 24-30 use Text::CSV; Link Here
24
use Encode qw( decode_utf8 );
24
use Encode qw( decode_utf8 );
25
25
26
use C4::Members;
26
use C4::Members;
27
use C4::Members::Attributes qw(:all);
28
27
29
use Koha::Libraries;
28
use Koha::Libraries;
30
use Koha::Patrons;
29
use Koha::Patrons;
Lines 156-163 sub import_patrons { Link Here
156
            next LINE;
155
            next LINE;
157
        }
156
        }
158
157
159
        # Set patron attributes if extended.
158
        # Generate patron attributes if extended.
160
        my $patron_attributes = $self->set_patron_attributes($extended, $borrower{patron_attributes}, \@feedback);
159
        my $patron_attributes = $self->generate_patron_attributes($extended, $borrower{patron_attributes}, \@feedback);
161
        if( $extended ) { delete $borrower{patron_attributes}; } # Not really a field in borrowers.
160
        if( $extended ) { delete $borrower{patron_attributes}; } # Not really a field in borrowers.
162
161
163
        # Default date enrolled and date expiry if not already set.
162
        # Default date enrolled and date expiry if not already set.
Lines 289-296 sub import_patrons { Link Here
289
            }
288
            }
290
            if ($extended) {
289
            if ($extended) {
291
                if ($ext_preserve) {
290
                if ($ext_preserve) {
292
                    my $old_attributes = $patron->extended_attributes->as_list;
293
294
                    $patron_attributes = $patron->extended_attributes->merge_with( $patron_attributes );
291
                    $patron_attributes = $patron->extended_attributes->merge_with( $patron_attributes );
295
                }
292
                }
296
                eval {
293
                eval {
Lines 456-484 sub set_column_keys { Link Here
456
    return @columnkeys;
453
    return @columnkeys;
457
}
454
}
458
455
459
=head2 set_patron_attributes
456
=head2 generate_patron_attributes
460
457
461
 my $patron_attributes = set_patron_attributes($extended, $borrower{patron_attributes}, $feedback);
458
 my $patron_attributes = generate_patron_attributes($extended, $borrower{patron_attributes}, $feedback);
462
459
463
Returns a reference to array of hashrefs data structure as expected by Koha::Patron->extended_attributes
460
Returns a Koha::Patron::Attributes as expected by Koha::Patron->extended_attributes
464
461
465
=cut
462
=cut
466
463
467
sub set_patron_attributes {
464
sub generate_patron_attributes {
468
    my ($self, $extended, $patron_attributes, $feedback) = @_;
465
    my ($self, $extended, $string, $feedback) = @_;
469
466
470
    unless( $extended ) { return; }
467
    unless( $extended ) { return; }
471
    unless( defined($patron_attributes) ) { return; }
468
    unless( defined $string ) { return; }
472
469
473
    # Fixup double quotes in case we are passed smart quotes
470
    # Fixup double quotes in case we are passed smart quotes
474
    $patron_attributes =~ s/\xe2\x80\x9c/"/g;
471
    $string =~ s/\xe2\x80\x9c/"/g;
475
    $patron_attributes =~ s/\xe2\x80\x9d/"/g;
472
    $string =~ s/\xe2\x80\x9d/"/g;
476
473
477
    push (@$feedback, { feedback => 1, name => 'attribute string', value => $patron_attributes });
474
    push (@$feedback, { feedback => 1, name => 'attribute string', value => $string });
478
475
    return [] unless $string; # Unit tests want the feedback, is it really needed?
479
    my $result = extended_attributes_code_value_arrayref($patron_attributes);
476
480
477
    my $csv = Text::CSV->new({binary => 1});  # binary needed for non-ASCII Unicode
481
    return $result;
478
    my $ok   = $csv->parse($string);  # parse field again to get subfields!
479
    my @list = $csv->fields();
480
    my @patron_attributes =
481
      sort { $a->{code} cmp $b->{code} || $a->{value} cmp $b->{value} }
482
      map {
483
        my @arr = split /:/, $_, 2;
484
        { code => $arr[0], attribute => $arr[1] }
485
      } @list;
486
    return \@patron_attributes;
487
    # TODO: error handling (check $ok)
482
}
488
}
483
489
484
=head2 check_branch_code
490
=head2 check_branch_code
(-)a/members/memberentry.pl (-1 lines)
Lines 30-36 use C4::Auth; Link Here
30
use C4::Context;
30
use C4::Context;
31
use C4::Output;
31
use C4::Output;
32
use C4::Members;
32
use C4::Members;
33
use C4::Members::Attributes;
34
use C4::Koha;
33
use C4::Koha;
35
use C4::Log;
34
use C4::Log;
36
use C4::Letters;
35
use C4::Letters;
(-)a/t/db_dependent/Koha/Patrons/Import.t (-6 / +7 lines)
Lines 51-57 subtest 'test_methods' => sub { Link Here
51
                   'set_attribute_types',
51
                   'set_attribute_types',
52
                   'prepare_columns',
52
                   'prepare_columns',
53
                   'set_column_keys',
53
                   'set_column_keys',
54
                   'set_patron_attributes',
54
                   'generate_patron_attributes',
55
                   'check_branch_code',
55
                   'check_branch_code',
56
                   'format_dates',
56
                   'format_dates',
57
                  );
57
                  );
Lines 214-219 my $params_4 = { file => $handle_4, matchpoint => $attribute->{code}, }; Link Here
214
214
215
# When ...
215
# When ...
216
my $result_4 = $patrons_import->import_patrons($params_4);
216
my $result_4 = $patrons_import->import_patrons($params_4);
217
use Data::Printer colored => 1; warn p $result_4;
217
218
218
# Then ...
219
# Then ...
219
is($result_4->{already_in_db}, 0, 'Got the expected 0 already_in_db from import_patrons with extended user');
220
is($result_4->{already_in_db}, 0, 'Got the expected 0 already_in_db from import_patrons with extended user');
Lines 525-543 subtest 'test_set_column_keys' => sub { Link Here
525
    is(scalar @columnkeys_1, @columns - 1 + $extended, 'Got the expected array size from set column keys with extended');
526
    is(scalar @columnkeys_1, @columns - 1 + $extended, 'Got the expected array size from set column keys with extended');
526
};
527
};
527
528
528
subtest 'test_set_patron_attributes' => sub {
529
subtest 'test_generate_patron_attributes' => sub {
529
    plan tests => 13;
530
    plan tests => 13;
530
531
531
    # Given ... nothing at all
532
    # Given ... nothing at all
532
    # When ... Then ...
533
    # When ... Then ...
533
    my $result_0 = $patrons_import->set_patron_attributes(undef, undef, undef);
534
    my $result_0 = $patrons_import->generate_patron_attributes(undef, undef, undef);
534
    is($result_0, undef, 'Got the expected undef from set patron attributes with nothing');
535
    is($result_0, undef, 'Got the expected undef from set patron attributes with nothing');
535
536
536
    # Given ... not extended.
537
    # Given ... not extended.
537
    my $extended_1 = 0;
538
    my $extended_1 = 0;
538
539
539
    # When ... Then ...
540
    # When ... Then ...
540
    my $result_1 = $patrons_import->set_patron_attributes($extended_1, undef, undef);
541
    my $result_1 = $patrons_import->generate_patron_attributes($extended_1, undef, undef);
541
    is($result_1, undef, 'Got the expected undef from set patron attributes with not extended');
542
    is($result_1, undef, 'Got the expected undef from set patron attributes with not extended');
542
543
543
    # Given ... NO patrons attributes
544
    # Given ... NO patrons attributes
Lines 546-552 subtest 'test_set_patron_attributes' => sub { Link Here
546
    my @feedback_2;
547
    my @feedback_2;
547
548
548
    # When ...
549
    # When ...
549
    my $result_2 = $patrons_import->set_patron_attributes($extended_2, $patron_attributes_2, \@feedback_2);
550
    my $result_2 = $patrons_import->generate_patron_attributes($extended_2, $patron_attributes_2, \@feedback_2);
550
551
551
    # Then ...
552
    # Then ...
552
    is($result_2, undef, 'Got the expected undef from set patron attributes with no patrons attributes');
553
    is($result_2, undef, 'Got the expected undef from set patron attributes with no patrons attributes');
Lines 557-563 subtest 'test_set_patron_attributes' => sub { Link Here
557
    my @feedback_3;
558
    my @feedback_3;
558
559
559
    # When ...
560
    # When ...
560
    my $result_3 = $patrons_import->set_patron_attributes($extended_2, $patron_attributes_3, \@feedback_3);
561
    my $result_3 = $patrons_import->generate_patron_attributes($extended_2, $patron_attributes_3, \@feedback_3);
561
562
562
    # Then ...
563
    # Then ...
563
    ok($result_3, 'Got some data back from set patron attributes');
564
    ok($result_3, 'Got some data back from set patron attributes');
(-)a/t/db_dependent/Members/Attributes.t (-228 lines)
Lines 1-228 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Copyright 2014  Biblibre SARL
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
use C4::Members;
24
use Koha::Database;
25
use t::lib::TestBuilder;
26
use t::lib::Mocks;
27
28
use Test::Exception;
29
use Test::More tests => 33;
30
31
use_ok('C4::Members::Attributes');
32
33
my $schema = Koha::Database->schema;
34
$schema->storage->txn_begin;
35
my $builder = t::lib::TestBuilder->new;
36
my $dbh = C4::Context->dbh;
37
$dbh->{RaiseError} = 1;
38
39
$dbh->do(q|DELETE FROM issues|);
40
$dbh->do(q|DELETE FROM borrowers|);
41
$dbh->do(q|DELETE FROM borrower_attributes|);
42
$dbh->do(q|DELETE FROM borrower_attribute_types|);
43
my $library = $builder->build({
44
    source => 'Branch',
45
});
46
47
my $patron = $builder->build(
48
    {   source => 'Borrower',
49
        value  => {
50
            firstname    => 'my firstname',
51
            surname      => 'my surname',
52
            branchcode => $library->{branchcode},
53
        }
54
    }
55
);
56
t::lib::Mocks::mock_userenv({ branchcode => $library->{branchcode} });
57
my $borrowernumber = $patron->{borrowernumber};
58
59
my $attribute_type1 = Koha::Patron::Attribute::Type->new(
60
    {
61
        code        => 'my code1',
62
        description => 'my description1',
63
        unique_id   => 1
64
    }
65
)->store;
66
my $attribute_type2 = Koha::Patron::Attribute::Type->new(
67
    {
68
        code             => 'my code2',
69
        description      => 'my description2',
70
        opac_display     => 1,
71
        staff_searchable => 1
72
    }
73
)->store;
74
75
my $new_library = $builder->build( { source => 'Branch' } );
76
my $attribute_type_limited = Koha::Patron::Attribute::Type->new(
77
    { code => 'my code3', description => 'my description3' } )->store;
78
$attribute_type_limited->library_limits( [ $new_library->{branchcode} ] );
79
80
$patron = Koha::Patrons->find($borrowernumber);
81
my $borrower_attributes = $patron->extended_attributes;
82
is( $borrower_attributes->count, 0, 'extended_attributes returns the correct number of borrower attributes' );
83
84
my $attributes = [
85
    {
86
        attribute => 'my attribute1',
87
        code => $attribute_type1->code(),
88
    },
89
    {
90
        attribute => 'my attribute2',
91
        code => $attribute_type2->code(),
92
    },
93
    {
94
        attribute => 'my attribute limited',
95
        code => $attribute_type_limited->code(),
96
    }
97
];
98
99
$patron->extended_attributes->filter_by_branch_limitations->delete;
100
my $set_borrower_attributes = $patron->extended_attributes($attributes);
101
is( ref($set_borrower_attributes), 'Koha::Patron::Attributes', '');
102
is( $set_borrower_attributes->count, 3, '');
103
$borrower_attributes = $patron->extended_attributes;
104
is( $borrower_attributes->count, 3, 'extended_attributes returns the correct number of borrower attributes' );
105
my $attr_0 = $borrower_attributes->next;
106
is( $attr_0->code, $attributes->[0]->{code}, 'setter for extended_attributes sestores the correct code correctly' );
107
is( $attr_0->type->description, $attribute_type1->description(), 'setter for extended_attributes stores the field description correctly' );
108
is( $attr_0->attribute, $attributes->[0]->{attribute}, 'setter for extended_attributes stores the field value correctly' );
109
my $attr_1 = $borrower_attributes->next;
110
is( $attr_1->code, $attributes->[1]->{code}, 'setter for extended_attributes stores the field code correctly' );
111
is( $attr_1->type->description, $attribute_type2->description(), 'setter for extended_attributes stores the field description correctly' );
112
is( $attr_1->attribute, $attributes->[1]->{attribute}, 'setter for extended_attributes stores the field value correctly' );
113
114
$attributes = [
115
    {
116
        attribute => 'my attribute1',
117
        code => $attribute_type1->code(),
118
    },
119
    {
120
        attribute => 'my attribute2',
121
        code => $attribute_type2->code(),
122
    }
123
];
124
$patron->extended_attributes->filter_by_branch_limitations->delete;
125
$patron->extended_attributes($attributes);
126
$borrower_attributes = $patron->extended_attributes;
127
is( $borrower_attributes->count, 3, 'setter for extended_attributes should not have removed the attributes limited to another branch' );
128
129
# TODO This is not implemented yet
130
#$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, undef, 'branch_limited');
131
#is( @$borrower_attributes, 2, 'GetBorrowerAttributes returns the correct number of borrower attributes filtered on library' );
132
133
$patron = Koha::Patrons->find($borrowernumber);
134
my $extended_attributes = $patron->extended_attributes;
135
my $attribute_value = $extended_attributes->search({ code => 'my invalid code' });
136
is( $attribute_value->count, 0, 'non existent attribute should return empty result set');
137
$attribute_value = $patron->get_extended_attribute('my invalid code');
138
is( $attribute_value, undef, 'non existent attribute should undef');
139
140
$attribute_value = $patron->get_extended_attribute($attributes->[0]->{code});
141
is( $attribute_value->attribute, $attributes->[0]->{attribute}, 'get_extended_attribute returns the correct attribute value' );
142
$attribute_value = $patron->get_extended_attribute($attributes->[1]->{code});
143
is( $attribute_value->attribute, $attributes->[1]->{attribute}, 'get_extended_attribute returns the correct attribute value' );
144
145
146
my $attribute = {
147
    attribute => 'my attribute3',
148
    code => $attribute_type1->code(),
149
};
150
$patron->extended_attributes->search({'me.code' => $attribute->{code}})->filter_by_branch_limitations->delete;
151
$patron->add_extended_attribute($attribute);
152
$borrower_attributes = $patron->extended_attributes;
153
is( $borrower_attributes->count, 3, 'delete then add a new attribute does not change the number of borrower attributes' );
154
$attr_0 = $borrower_attributes->next;
155
is( $attr_0->code, $attribute->{code}, 'delete then add a new attribute updates the field code correctly' );
156
is( $attr_0->type->description, $attribute_type1->description(), 'delete then add a new attribute updates the field description correctly' );
157
is( $attr_0->attribute, $attribute->{attribute}, 'delete then add a new attribute updates the field value correctly' );
158
159
160
lives_ok { # Editing, new value, same patron
161
    Koha::Patron::Attribute->new(
162
        {
163
            code           => $attribute->{code},
164
            attribute      => 'new value',
165
            borrowernumber => $patron->borrowernumber
166
        }
167
    )->check_unique_id;
168
} 'no exception raised';
169
lives_ok { # Editing, same value, same patron
170
    Koha::Patron::Attribute->new(
171
        {
172
            code           => $attributes->[1]->{code},
173
            attribute      => $attributes->[1]->{attribute},
174
            borrowernumber => $patron->borrowernumber
175
        }
176
    )->check_unique_id;
177
} 'no exception raised';
178
throws_ok { # Creating a new one, but already exists!
179
    Koha::Patron::Attribute->new(
180
        { code => $attribute->{code}, attribute => $attribute->{attribute} } )
181
      ->check_unique_id;
182
} 'Koha::Exceptions::Patron::Attribute::UniqueIDConstraint';
183
184
185
$patron->get_extended_attribute($attribute->{code})->delete;
186
$borrower_attributes = $patron->extended_attributes;
187
is( $borrower_attributes->count, 2, 'delete attribute by code' );
188
$attr_0 = $borrower_attributes->next;
189
is( $attr_0->code, $attributes->[1]->{code}, 'delete attribute by code');
190
is( $attr_0->type->description, $attribute_type2->description(), 'delete attribute by code');
191
is( $attr_0->attribute, $attributes->[1]->{attribute}, 'delete attribute by code');
192
193
$patron->get_extended_attribute($attributes->[1]->{code})->delete;
194
$borrower_attributes = $patron->extended_attributes;
195
is( $borrower_attributes->count, 1, 'delete attribute by code' );
196
197
# Regression tests for bug 16504
198
t::lib::Mocks::mock_userenv({ branchcode => $new_library->{branchcode} });
199
my $another_patron = $builder->build_object(
200
    {   class  => 'Koha::Patrons',
201
        value  => {
202
            firstname    => 'my another firstname',
203
            surname      => 'my another surname',
204
            branchcode => $new_library->{branchcode},
205
        }
206
    }
207
);
208
$attributes = [
209
    {
210
        attribute => 'my attribute1',
211
        code => $attribute_type1->code(),
212
    },
213
    {
214
        attribute => 'my attribute2',
215
        code => $attribute_type2->code(),
216
    },
217
    {
218
        attribute => 'my attribute limited',
219
        code => $attribute_type_limited->code(),
220
    }
221
];
222
223
$another_patron->extended_attributes->filter_by_branch_limitations->delete;
224
$another_patron->extended_attributes($attributes);
225
$borrower_attributes = $another_patron->extended_attributes;
226
is( $borrower_attributes->count, 3, 'setter for extended_attributes should have added the 3 attributes for another patron');
227
$borrower_attributes = $patron->extended_attributes;
228
is( $borrower_attributes->count, 1, 'setter for extended_attributes should not have removed the attributes of other patrons' );
(-)a/t/db_dependent/Utils/Datatables_Members.t (-2 lines)
Lines 22-29 use Test::More tests => 51; Link Here
22
use C4::Context;
22
use C4::Context;
23
use C4::Members;
23
use C4::Members;
24
24
25
use C4::Members::Attributes;
26
27
use Koha::Library;
25
use Koha::Library;
28
use Koha::Patrons;
26
use Koha::Patrons;
29
use Koha::Patron::Categories;
27
use Koha::Patron::Categories;
(-)a/tools/modborrowers.pl (-2 lines)
Lines 30-36 use CGI qw ( -utf8 ); Link Here
30
use C4::Auth;
30
use C4::Auth;
31
use C4::Koha;
31
use C4::Koha;
32
use C4::Members;
32
use C4::Members;
33
use C4::Members::Attributes;
34
use C4::Output;
33
use C4::Output;
35
use List::MoreUtils qw /any uniq/;
34
use List::MoreUtils qw /any uniq/;
36
use Koha::DateUtils qw( dt_from_string );
35
use Koha::DateUtils qw( dt_from_string );
37
- 

Return to bug 20443