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

(-)a/C4/Letters.pm (-5 / +6 lines)
Lines 28-34 use Template; Link Here
28
use Module::Load::Conditional qw(can_load);
28
use Module::Load::Conditional qw(can_load);
29
29
30
use C4::Members;
30
use C4::Members;
31
use C4::Members::Attributes qw(GetBorrowerAttributes);
32
use C4::Log;
31
use C4::Log;
33
use C4::SMS;
32
use C4::SMS;
34
use C4::Debug;
33
use C4::Debug;
Lines 852-862 sub _parseletter { Link Here
852
    }
851
    }
853
852
854
    if ($table eq 'borrowers' && $letter->{content}) {
853
    if ($table eq 'borrowers' && $letter->{content}) {
855
        if ( my $attributes = GetBorrowerAttributes($values->{borrowernumber}) ) {
854
        my $patron = Koha::Patrons->find( $values->{borrowernumber} );
855
        if ( $patron ) {
856
            my $attributes = $patron->get_extended_attributes;
856
            my %attr;
857
            my %attr;
857
            foreach (@$attributes) {
858
            while ( my $attribute = $attributes->next ) {
858
                my $code = $_->{code};
859
                my $code = $attribute->code;
859
                my $val  = $_->{value_description} || $_->{value};
860
                my $val  = $attribute->description; # FIXME - we always display intranet description here!
860
                $val =~ s/\p{P}(?=$)//g if $val;
861
                $val =~ s/\p{P}(?=$)//g if $val;
861
                next unless $val gt '';
862
                next unless $val gt '';
862
                $attr{$code} ||= [];
863
                $attr{$code} ||= [];
(-)a/C4/Members/Attributes.pm (-50 / +1 lines)
Lines 29-35 our ($csv, $AttributeTypes); Link Here
29
29
30
BEGIN {
30
BEGIN {
31
    @ISA = qw(Exporter);
31
    @ISA = qw(Exporter);
32
    @EXPORT_OK = qw(GetBorrowerAttributes CheckUniqueness SetBorrowerAttributes
32
    @EXPORT_OK = qw(CheckUniqueness SetBorrowerAttributes
33
                    DeleteBorrowerAttribute UpdateBorrowerAttribute
33
                    DeleteBorrowerAttribute UpdateBorrowerAttribute
34
                    extended_attributes_code_value_arrayref extended_attributes_merge
34
                    extended_attributes_code_value_arrayref extended_attributes_merge
35
                    SearchIdMatchingAttribute);
35
                    SearchIdMatchingAttribute);
Lines 43-100 C4::Members::Attributes - manage extend patron attributes Link Here
43
=head1 SYNOPSIS
43
=head1 SYNOPSIS
44
44
45
  use C4::Members::Attributes;
45
  use C4::Members::Attributes;
46
  my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
47
46
48
=head1 FUNCTIONS
47
=head1 FUNCTIONS
49
48
50
=head2 GetBorrowerAttributes
51
52
  my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber[, $opac_only]);
53
54
Retrieve an arrayref of extended attributes associated with the
55
patron specified by C<$borrowernumber>.  Each entry in the arrayref
56
is a hashref containing the following keys:
57
58
code (attribute type code)
59
description (attribute type description)
60
value (attribute value)
61
value_description (attribute value description (if associated with an authorised value))
62
63
If the C<$opac_only> parameter is present and has a true value, only the attributes
64
marked for OPAC display are returned.
65
66
=cut
67
68
sub GetBorrowerAttributes {
69
    my $borrowernumber = shift;
70
    my $opac_only = @_ ? shift : 0;
71
72
    my $dbh = C4::Context->dbh();
73
    my $query = "SELECT code, description, attribute, lib, display_checkout, category_code, class
74
                 FROM borrower_attributes
75
                 JOIN borrower_attribute_types USING (code)
76
                 LEFT JOIN authorised_values ON (category = authorised_value_category AND attribute = authorised_value)
77
                 WHERE borrowernumber = ?";
78
    $query .= "\nAND opac_display = 1" if $opac_only;
79
    $query .= "\nORDER BY code, attribute";
80
    my $sth = $dbh->prepare_cached($query);
81
    $sth->execute($borrowernumber);
82
    my @results = ();
83
    while (my $row = $sth->fetchrow_hashref()) {
84
        push @results, {
85
            code              => $row->{'code'},
86
            description       => $row->{'description'},
87
            value             => $row->{'attribute'},
88
            value_description => $row->{'lib'},
89
            display_checkout  => $row->{'display_checkout'},
90
            category_code     => $row->{'category_code'},
91
            class             => $row->{'class'},
92
        }
93
    }
94
    $sth->finish;
95
    return \@results;
96
}
97
98
=head2 SearchIdMatchingAttribute
49
=head2 SearchIdMatchingAttribute
99
50
100
  my $matching_borrowernumbers = C4::Members::Attributes::SearchIdMatchingAttribute($filter);
51
  my $matching_borrowernumbers = C4::Members::Attributes::SearchIdMatchingAttribute($filter);
(-)a/Koha/Patron.pm (-7 / +6 lines)
Lines 1438-1457 sub generate_userid { Link Here
1438
     return $self;
1438
     return $self;
1439
}
1439
}
1440
1440
1441
=head3 attributes
1441
=head3 get_extended_attributes
1442
1442
1443
my $attributes = $patron->attributes
1443
my $attributes = $patron->get_extended_attributes
1444
1444
1445
Return object of Koha::Patron::Attributes type with all attributes set for this patron
1445
Return object of Koha::Patron::Attributes type with all attributes set for this patron
1446
1446
1447
=cut
1447
=cut
1448
1448
1449
sub attributes {
1449
sub get_extended_attributes {
1450
    my ( $self ) = @_;
1450
    my ( $self ) = @_;
1451
    return Koha::Patron::Attributes->search({
1451
    my $rs = $self->_result->borrower_attributes;
1452
        borrowernumber => $self->borrowernumber,
1452
    # We call search to use the filters in Koha::Patron::Attributes->search
1453
        branchcode     => $self->branchcode,
1453
    return Koha::Patron::Attributes->_new_from_dbic($rs)->search;
1454
    });
1455
}
1454
}
1456
1455
1457
=head3 lock
1456
=head3 lock
(-)a/Koha/Patron/Attribute.pm (-1 / +46 lines)
Lines 64-72 sub type { Link Here
64
64
65
    my $self = shift;
65
    my $self = shift;
66
66
67
    return Koha::Patron::Attribute::Types->find( $self->code );
67
    return scalar Koha::Patron::Attribute::Types->find( $self->code );
68
}
68
}
69
69
70
=head3
71
72
my $authorised_value = $attribute->authorised_value;
73
74
Return the Koha::AuthorisedValue object of this attribute when one is attached.
75
76
Return undef if this attribute is not attached to an authorised value
77
78
=cut
79
80
sub authorised_value {
81
    my ($self) = @_;
82
83
    return unless $self->type->authorised_value_category;
84
85
    my $av = Koha::AuthorisedValues->search(
86
        {
87
            category         => $self->type->authorised_value_category,
88
            authorised_value => $self->attribute,
89
        }
90
    );
91
    return unless $av->count; # Data inconsistency
92
    return $av->next;
93
}
94
95
=head3
96
97
my $description = $patron_attribute->description;
98
99
Return the value of this attribute or the description of the authorised value (when attached).
100
101
This method must be called when the authorised value's description must be
102
displayed instead of the code.
103
104
=cut
105
106
sub description {
107
    my ( $self) = @_;
108
    if ( $self->type->authorised_value_category ) {
109
        return $self->authorised_value->lib;
110
    }
111
    return $self->attribute;
112
}
113
114
70
=head2 Internal methods
115
=head2 Internal methods
71
116
72
=head3 _check_repeatable
117
=head3 _check_repeatable
(-)a/Koha/Patron/Attributes.pm (+1 lines)
Lines 60-65 sub search { Link Here
60
            },
60
            },
61
        } : {};
61
        } : {};
62
    $attributes //= {};
62
    $attributes //= {};
63
    unless ( exists $attributes->{order_by} ) { $attributes->{order_by} = ['code', 'attribute'] }
63
    return $self->SUPER::search( { %$params, %$or }, { %$attributes, %$join } );
64
    return $self->SUPER::search( { %$params, %$or }, { %$attributes, %$join } );
64
}
65
}
65
66
(-)a/Koha/Patrons/Import.pm (-1 / +1 lines)
Lines 290-296 sub import_patrons { Link Here
290
            }
290
            }
291
            if ($extended) {
291
            if ($extended) {
292
                if ($ext_preserve) {
292
                if ($ext_preserve) {
293
                    my $old_attributes = GetBorrowerAttributes($borrowernumber);
293
                    my $old_attributes = $patron->get_extended_attributes->as_list;
294
                    $patron_attributes = extended_attributes_merge( $old_attributes, $patron_attributes );
294
                    $patron_attributes = extended_attributes_merge( $old_attributes, $patron_attributes );
295
                }
295
                }
296
                push @errors, { unknown_error => 1 }
296
                push @errors, { unknown_error => 1 }
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc (-3 / +7 lines)
Lines 71-79 Link Here
71
    [% END %]
71
    [% END %]
72
72
73
    [% IF Koha.Preference('ExtendedPatronAttributes') %]
73
    [% IF Koha.Preference('ExtendedPatronAttributes') %]
74
        [% FOREACH extendedattribute IN patron.attributes %]
74
        [% FOREACH extendedattribute IN patron.get_extended_attributes %]
75
            [% IF ( extendedattribute.display_checkout ) %]
75
            [% IF ( extendedattribute.type.display_checkout ) %] [%# FIXME We should filter in the line above %]
76
                <li class="patronattribute"><span class="patronattributelabel">[% extendedattribute.type_description | html %]</span> : [% IF ( extendedattribute.value_description ) %][% extendedattribute.value_description | html %][% ELSE %][% extendedattribute.attribute | html %][% END %]</li>
76
                [% IF ( extendedattribute.attribute ) %] [%# FIXME Why that? why not if == 0? %]
77
                    <li class="patronattribute">
78
                        <span class="patronattributelabel">[% extendedattribute.type.description | html %]</span>: [% extendedattribute.description | html %]
79
                    </li>
80
                [% END %]
77
            [% END %]
81
            [% END %]
78
        [% END %]
82
        [% END %]
79
    [% END %]
83
    [% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt (-6 / +2 lines)
Lines 381-392 Link Here
381
                                                    <ol>
381
                                                    <ol>
382
                                                        [% FOREACH item IN attribute.items %]
382
                                                        [% FOREACH item IN attribute.items %]
383
                                                            <li>
383
                                                            <li>
384
                                                                <span class="label">[% item.description | html %]: </span>
384
                                                                <span class="label">[% item.type.description | html %]: </span>
385
                                                                [% IF ( item.value_description ) %]
385
                                                                [% item.description | html_line_break %]
386
                                                                    [% item.value_description | html %]
387
                                                                [% ELSE %]
388
                                                                    [% item.value| html | html_line_break %]
389
                                                                [% END %]
390
                                                            </li>
386
                                                            </li>
391
                                                        [% END %]
387
                                                        [% END %]
392
                                                    </ol>
388
                                                    </ol>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/modborrowers.tt (-1 / +2 lines)
Lines 191-197 Link Here
191
                                                    <td>[% borrower.debarredcomment | html %]</td>
191
                                                    <td>[% borrower.debarredcomment | html %]</td>
192
                                                    [% FOREACH pa IN borrower.patron_attributes %]
192
                                                    [% FOREACH pa IN borrower.patron_attributes %]
193
                                                        [% IF ( pa.code ) %]
193
                                                        [% IF ( pa.code ) %]
194
                                                            <td>[% pa.code | html %]=[% pa.value | html %]</td>
194
                                                        [%# Replace pa.attribute with pa.description if we prefer to display the description %]
195
                                                            <td>[% pa.code | html %]=[% pa.attribute | html %]</td>
195
                                                        [% ELSE %]
196
                                                        [% ELSE %]
196
                                                            <td></td>
197
                                                            <td></td>
197
                                                        [% END %]
198
                                                        [% END %]
(-)a/members/memberentry.pl (-3 / +4 lines)
Lines 857-869 sub patron_attributes_form { Link Here
857
        $template->param(no_patron_attribute_types => 1);
857
        $template->param(no_patron_attribute_types => 1);
858
        return;
858
        return;
859
    }
859
    }
860
    my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
860
    my $patron = Koha::Patrons->find($borrowernumber); # Already fetched but outside of this sub
861
    my @classes = uniq( map {$_->{class}} @$attributes );
861
    my @attributes = $patron->get_extended_attributes->as_list; # FIXME Must be improved!
862
    my @classes = uniq( map {$_->type->class} @attributes );
862
    @classes = sort @classes;
863
    @classes = sort @classes;
863
864
864
    # map patron's attributes into a more convenient structure
865
    # map patron's attributes into a more convenient structure
865
    my %attr_hash = ();
866
    my %attr_hash = ();
866
    foreach my $attr (@$attributes) {
867
    foreach my $attr (@attributes) {
867
        push @{ $attr_hash{$attr->{code}} }, $attr;
868
        push @{ $attr_hash{$attr->{code}} }, $attr;
868
    }
869
    }
869
870
(-)a/members/moremember.pl (-5 / +4 lines)
Lines 35-41 use C4::Output; Link Here
35
use C4::Members::AttributeTypes;
35
use C4::Members::AttributeTypes;
36
use C4::Form::MessagingPreferences;
36
use C4::Form::MessagingPreferences;
37
use List::MoreUtils qw/uniq/;
37
use List::MoreUtils qw/uniq/;
38
use C4::Members::Attributes qw(GetBorrowerAttributes);
39
use Koha::Patron::Debarments qw(GetDebarments);
38
use Koha::Patron::Debarments qw(GetDebarments);
40
use Koha::Patron::Messages;
39
use Koha::Patron::Messages;
41
use Koha::DateUtils;
40
use Koha::DateUtils;
Lines 131-145 $template->param( Link Here
131
);
130
);
132
131
133
if (C4::Context->preference('ExtendedPatronAttributes')) {
132
if (C4::Context->preference('ExtendedPatronAttributes')) {
134
    my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
133
    my @attributes = $patron->get_extended_attributes->as_list; # FIXME Must be improved!
135
    my @classes = uniq( map {$_->{class}} @$attributes );
134
    my @classes = uniq( map {$_->type->class} @attributes );
136
    @classes = sort @classes;
135
    @classes = sort @classes;
137
136
138
    my @attributes_loop;
137
    my @attributes_loop;
139
    for my $class (@classes) {
138
    for my $class (@classes) {
140
        my @items;
139
        my @items;
141
        for my $attr (@$attributes) {
140
        for my $attr (@attributes) {
142
            push @items, $attr if $attr->{class} eq $class
141
            push @items, $attr if $attr->type->class eq $class
143
        }
142
        }
144
        my $av = Koha::AuthorisedValues->search({ category => 'PA_CLASS', authorised_value => $class });
143
        my $av = Koha::AuthorisedValues->search({ category => 'PA_CLASS', authorised_value => $class });
145
        my $lib = $av->count ? $av->next->lib : $class;
144
        my $lib = $av->count ? $av->next->lib : $class;
(-)a/opac/opac-memberentry.pl (-1 lines)
Lines 26-32 use String::Random qw( random_string ); Link Here
26
use C4::Auth;
26
use C4::Auth;
27
use C4::Output;
27
use C4::Output;
28
use C4::Members;
28
use C4::Members;
29
use C4::Members::Attributes qw( GetBorrowerAttributes );
30
use C4::Form::MessagingPreferences;
29
use C4::Form::MessagingPreferences;
31
use Koha::AuthUtils;
30
use Koha::AuthUtils;
32
use Koha::Patrons;
31
use Koha::Patrons;
(-)a/t/db_dependent/Auth_with_ldap.t (-5 / +1 lines)
Lines 206-216 subtest 'checkpw_ldap tests' => sub { Link Here
206
206
207
        C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' );
207
        C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' );
208
        ok(
208
        ok(
209
            @{
209
            Koha::Patrons->find($borrower->{borrowernumber})->get_extended_attributes->count,
210
                C4::Members::Attributes::GetBorrowerAttributes(
211
                    $borrower->{borrowernumber}
212
                )
213
            },
214
            'Extended attributes are not deleted'
210
            'Extended attributes are not deleted'
215
        );
211
        );
216
212
(-)a/t/db_dependent/Koha/Patron/Modifications.t (-10 / +11 lines)
Lines 30-36 use Try::Tiny; Link Here
30
30
31
use C4::Context;
31
use C4::Context;
32
use C4::Members;
32
use C4::Members;
33
use C4::Members::Attributes qw( GetBorrowerAttributes );
34
use Koha::Patrons;
33
use Koha::Patrons;
35
use Koha::Patron::Attribute;
34
use Koha::Patron::Attribute;
36
35
Lines 175-188 subtest 'approve tests' => sub { Link Here
175
    );
174
    );
176
    is( $patron->firstname, 'Kyle',
175
    is( $patron->firstname, 'Kyle',
177
        'Patron modification set the right firstname' );
176
        'Patron modification set the right firstname' );
178
    my @patron_attributes = GetBorrowerAttributes( $patron->borrowernumber );
177
    my $patron_attributes = $patron->get_extended_attributes;
179
    is( $patron_attributes[0][0]->{code},
178
    my $attribute_1 = $patron_attributes->next;
179
    is( $attribute_1->code,
180
        'CODE_1', 'Patron modification correctly saved attribute code' );
180
        'CODE_1', 'Patron modification correctly saved attribute code' );
181
    is( $patron_attributes[0][0]->{value},
181
    is( $attribute_1->attribute,
182
        'VALUE_1', 'Patron modification correctly saved attribute value' );
182
        'VALUE_1', 'Patron modification correctly saved attribute value' );
183
    is( $patron_attributes[0][1]->{code},
183
    my $attribute_2 = $patron_attributes->next;
184
    is( $attribute_2->code,
184
        'CODE_2', 'Patron modification correctly saved attribute code' );
185
        'CODE_2', 'Patron modification correctly saved attribute code' );
185
    is( $patron_attributes[0][1]->{value},
186
    is( $attribute_2->attribute,
186
        0, 'Patron modification correctly saved attribute with value 0, not confused with delete' );
187
        0, 'Patron modification correctly saved attribute with value 0, not confused with delete' );
187
188
188
    # Create a new Koha::Patron::Modification, skip extended_attributes to
189
    # Create a new Koha::Patron::Modification, skip extended_attributes to
Lines 219-225 subtest 'approve tests' => sub { Link Here
219
    )->store();
220
    )->store();
220
    ok( $patron_modification->approve,
221
    ok( $patron_modification->approve,
221
        'Patron modification correctly approved' );
222
        'Patron modification correctly approved' );
222
    @patron_attributes
223
    my @patron_attributes
223
        = map { $_->unblessed }
224
        = map { $_->unblessed }
224
        Koha::Patron::Attributes->search(
225
        Koha::Patron::Attributes->search(
225
        { borrowernumber => $patron->borrowernumber } );
226
        { borrowernumber => $patron->borrowernumber } );
Lines 232-243 subtest 'approve tests' => sub { Link Here
232
    is( $patron_attributes[1]->{code},
233
    is( $patron_attributes[1]->{code},
233
        'CODE_2', 'Attribute updated correctly (code)' );
234
        'CODE_2', 'Attribute updated correctly (code)' );
234
    is( $patron_attributes[1]->{attribute},
235
    is( $patron_attributes[1]->{attribute},
235
        'Tomasito', 'Attribute updated correctly (attribute)' );
236
        'None', 'Attribute updated correctly (attribute)' );
236
237
237
    is( $patron_attributes[2]->{code},
238
    is( $patron_attributes[2]->{code},
238
        'CODE_2', 'Attribute updated correctly (code)' );
239
        'CODE_2', 'Attribute updated correctly (code)' );
239
    is( $patron_attributes[2]->{attribute},
240
    is( $patron_attributes[2]->{attribute},
240
        'None', 'Attribute updated correctly (attribute)' );
241
        'Tomasito', 'Attribute updated correctly (attribute)' );
241
242
242
    my $empty_code_json = '[{"code":"CODE_2","value":""}]';
243
    my $empty_code_json = '[{"code":"CODE_2","value":""}]';
243
    $verification_token = md5_hex( time() . {} . rand() . {} . $$ );
244
    $verification_token = md5_hex( time() . {} . rand() . {} . $$ );
Lines 251-257 subtest 'approve tests' => sub { Link Here
251
    )->store();
252
    )->store();
252
    ok( $patron_modification->approve,
253
    ok( $patron_modification->approve,
253
        'Patron modification correctly approved' );
254
        'Patron modification correctly approved' );
254
    @patron_attributes
255
    $patron_attributes
255
        = map { $_->unblessed }
256
        = map { $_->unblessed }
256
        Koha::Patron::Attributes->search(
257
        Koha::Patron::Attributes->search(
257
        { borrowernumber => $patron->borrowernumber } );
258
        { borrowernumber => $patron->borrowernumber } );
(-)a/t/db_dependent/Koha/Patrons.t (-1 / +10 lines)
Lines 2020-2026 subtest 'anonymize' => sub { Link Here
2020
$schema->storage->txn_rollback;
2020
$schema->storage->txn_rollback;
2021
2021
2022
subtest 'get_extended_attributes' => sub {
2022
subtest 'get_extended_attributes' => sub {
2023
    plan tests => 7;
2023
    plan tests => 9;
2024
    my $schema = Koha::Database->new->schema;
2024
    my $schema = Koha::Database->new->schema;
2025
    $schema->storage->txn_begin;
2025
    $schema->storage->txn_begin;
2026
2026
Lines 2092-2096 subtest 'get_extended_attributes' => sub { Link Here
2092
    my $non_existent = $patron_2->get_extended_attribute_value( 'not_exist' );
2092
    my $non_existent = $patron_2->get_extended_attribute_value( 'not_exist' );
2093
    is( $non_existent, undef, 'Koha::Patron->get_extended_attribute_value must return undef if the attribute does not exist' );
2093
    is( $non_existent, undef, 'Koha::Patron->get_extended_attribute_value must return undef if the attribute does not exist' );
2094
2094
2095
    # Test branch limitations
2096
    set_logged_in_user($patron_2);
2097
    C4::Members::Attributes::SetBorrowerAttributes($patron_1->borrowernumber, $attributes_for_1);
2098
    $extended_attributes_for_1 = $patron_1->get_extended_attributes;
2099
    is( $extended_attributes_for_1->count, 2, 'There should be 2 attributes for patron 1, the limited one should not be returned');
2100
2101
    my $limited_value = $patron_1->get_extended_attribute_value( $attribute_type_limited->code );
2102
    is( $limited_value, undef, );
2103
2095
    $schema->storage->txn_rollback;
2104
    $schema->storage->txn_rollback;
2096
};
2105
};
(-)a/t/db_dependent/Members/Attributes.t (-54 / +43 lines)
Lines 26-32 use Koha::Database; Link Here
26
use t::lib::TestBuilder;
26
use t::lib::TestBuilder;
27
use t::lib::Mocks;
27
use t::lib::Mocks;
28
28
29
use Test::More tests => 46;
29
use Test::More tests => 41;
30
30
31
use_ok('C4::Members::Attributes');
31
use_ok('C4::Members::Attributes');
32
32
Lines 70-81 my $attribute_type_limited = C4::Members::AttributeTypes->new('my code3', 'my de Link Here
70
$attribute_type_limited->branches([ $new_library->{branchcode} ]);
70
$attribute_type_limited->branches([ $new_library->{branchcode} ]);
71
$attribute_type_limited->store;
71
$attribute_type_limited->store;
72
72
73
my $borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes();
74
ok(1);
75
#is( @$borrower_attributes, 0, 'GetBorrowerAttributes without the borrower number returns an empty array' );
76
$patron = Koha::Patrons->find($borrowernumber);
73
$patron = Koha::Patrons->find($borrowernumber);
77
$borrower_attributes = $patron->get_extended_attributes;
74
my $borrower_attributes = $patron->get_extended_attributes;
78
is( $borrower_attributes->count, 0, 'GetBorrowerAttributes returns the correct number of borrower attributes' );
75
is( $borrower_attributes->count, 0, 'get_extended_attributes returns the correct number of borrower attributes' );
79
76
80
my $attributes = [
77
my $attributes = [
81
    {
78
    {
Lines 92-119 my $attributes = [ Link Here
92
    }
89
    }
93
];
90
];
94
91
95
my $set_borrower_attributes = C4::Members::Attributes::SetBorrowerAttributes();
92
my $set_borrower_attributes = C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $attributes);
96
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes();
97
is( @$borrower_attributes, 0, 'SetBorrowerAttributes without arguments does not add borrower attributes' );
98
99
$set_borrower_attributes = C4::Members::Attributes::SetBorrowerAttributes($borrowernumber);
100
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes();
101
is( @$borrower_attributes, 0, 'SetBorrowerAttributes without the attributes does not add borrower attributes' );
102
103
$set_borrower_attributes = C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $attributes);
104
is( $set_borrower_attributes, 1, 'SetBorrowerAttributes returns the success code' );
93
is( $set_borrower_attributes, 1, 'SetBorrowerAttributes returns the success code' );
105
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes();
94
$borrower_attributes = $patron->get_extended_attributes;
106
is( @$borrower_attributes, 0, 'GetBorrowerAttributes without the borrower number returns an empty array' );
95
is( $borrower_attributes->count, 3, 'get_extended_attributes returns the correct number of borrower attributes' );
107
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
96
my $attr_0 = $borrower_attributes->next;
108
is( @$borrower_attributes, 3, 'GetBorrowerAttributes returns the correct number of borrower attributes' );
97
is( $attr_0->code, $attributes->[0]->{code}, 'SetBorrowerAttributes stores the correct code correctly' );
109
is( $borrower_attributes->[0]->{code}, $attributes->[0]->{code}, 'SetBorrowerAttributes stores the correct code correctly' );
98
is( $attr_0->type->description, $attribute_type1->description(), 'SetBorrowerAttributes stores the field description correctly' );
110
is( $borrower_attributes->[0]->{description}, $attribute_type1->description(), 'SetBorrowerAttributes stores the field description correctly' );
99
is( $attr_0->attribute, $attributes->[0]->{value}, 'SetBorrowerAttributes stores the field value correctly' );
111
is( $borrower_attributes->[0]->{value}, $attributes->[0]->{value}, 'SetBorrowerAttributes stores the field value correctly' );
100
my $attr_1 = $borrower_attributes->next;
112
is( $borrower_attributes->[1]->{code}, $attributes->[1]->{code}, 'SetBorrowerAttributes stores the field code correctly' );
101
is( $attr_1->code, $attributes->[1]->{code}, 'SetBorrowerAttributes stores the field code correctly' );
113
is( $borrower_attributes->[1]->{description}, $attribute_type2->description(), 'SetBorrowerAttributes stores the field description correctly' );
102
is( $attr_1->type->description, $attribute_type2->description(), 'SetBorrowerAttributes stores the field description correctly' );
114
is( $borrower_attributes->[1]->{value}, $attributes->[1]->{value}, 'SetBorrowerAttributes stores the field value correctly' );
103
is( $attr_1->attribute, $attributes->[1]->{value}, 'SetBorrowerAttributes stores the field value correctly' );
115
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
116
is( @$borrower_attributes, 3, 'GetBorrowerAttributes returns the correct number of borrower attributes' );
117
104
118
$attributes = [
105
$attributes = [
119
    {
106
    {
Lines 126-133 $attributes = [ Link Here
126
    }
113
    }
127
];
114
];
128
C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $attributes);
115
C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $attributes);
129
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
116
$borrower_attributes = $patron->get_extended_attributes;
130
is( @$borrower_attributes, 3, 'SetBorrowerAttributes should not have removed the attributes limited to another branch' );
117
is( $borrower_attributes->count, 3, 'SetBorrowerAttributes should not have removed the attributes limited to another branch' );
131
118
132
# TODO This is not implemented yet
119
# TODO This is not implemented yet
133
#$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, undef, 'branch_limited');
120
#$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, undef, 'branch_limited');
Lines 151-161 my $attribute = { Link Here
151
    code => $attribute_type1->code(),
138
    code => $attribute_type1->code(),
152
};
139
};
153
C4::Members::Attributes::UpdateBorrowerAttribute($borrowernumber, $attribute);
140
C4::Members::Attributes::UpdateBorrowerAttribute($borrowernumber, $attribute);
154
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
141
$borrower_attributes = $patron->get_extended_attributes;
155
is( @$borrower_attributes, 3, 'UpdateBorrowerAttribute does not change the number of borrower attributes' );
142
is( $borrower_attributes->count, 3, 'UpdateBorrowerAttribute does not change the number of borrower attributes' );
156
is( $borrower_attributes->[0]->{code}, $attribute->{code}, 'UpdateBorrowerAttribute updates the field code correctly' );
143
$attr_0 = $borrower_attributes->next;
157
is( $borrower_attributes->[0]->{description}, $attribute_type1->description(), 'UpdateBorrowerAttribute updates the field description correctly' );
144
is( $attr_0->code, $attribute->{code}, 'UpdateBorrowerAttribute updates the field code correctly' );
158
is( $borrower_attributes->[0]->{value}, $attribute->{attribute}, 'UpdateBorrowerAttribute updates the field value correctly' );
145
is( $attr_0->type->description, $attribute_type1->description(), 'UpdateBorrowerAttribute updates the field description correctly' );
146
is( $attr_0->attribute, $attribute->{attribute}, 'UpdateBorrowerAttribute updates the field value correctly' );
159
147
160
148
161
my $check_uniqueness = C4::Members::Attributes::CheckUniqueness();
149
my $check_uniqueness = C4::Members::Attributes::CheckUniqueness();
Lines 187-216 for my $attr( split(' ', $attributes->[1]->{value}) ) { Link Here
187
175
188
176
189
C4::Members::Attributes::DeleteBorrowerAttribute();
177
C4::Members::Attributes::DeleteBorrowerAttribute();
190
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
178
$borrower_attributes = $patron->get_extended_attributes;
191
is( @$borrower_attributes, 3, 'DeleteBorrowerAttribute without arguments deletes nothing' );
179
is( $borrower_attributes->count, 3, 'DeleteBorrowerAttribute without arguments deletes nothing' );
192
C4::Members::Attributes::DeleteBorrowerAttribute($borrowernumber);
180
C4::Members::Attributes::DeleteBorrowerAttribute($borrowernumber);
193
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
181
$borrower_attributes = $patron->get_extended_attributes;
194
is( @$borrower_attributes, 3, 'DeleteBorrowerAttribute without the attribute deletes nothing' );
182
is( $borrower_attributes->count, 3, 'DeleteBorrowerAttribute without the attribute deletes nothing' );
195
C4::Members::Attributes::DeleteBorrowerAttribute(undef, $attribute);
183
C4::Members::Attributes::DeleteBorrowerAttribute(undef, $attribute);
196
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
184
$borrower_attributes = $patron->get_extended_attributes;
197
is( @$borrower_attributes, 3, 'DeleteBorrowerAttribute with a undef borrower number deletes nothing' );
185
is( $borrower_attributes->count, 3, 'DeleteBorrowerAttribute with a undef borrower number deletes nothing' );
198
186
199
C4::Members::Attributes::DeleteBorrowerAttribute($borrowernumber, $attribute);
187
C4::Members::Attributes::DeleteBorrowerAttribute($borrowernumber, $attribute);
200
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
188
$borrower_attributes = $patron->get_extended_attributes;
201
is( @$borrower_attributes, 2, 'DeleteBorrowerAttribute deletes a borrower attribute' );
189
is( $borrower_attributes->count, 2, 'DeleteBorrowerAttribute deletes a borrower attribute' );
202
is( $borrower_attributes->[0]->{code}, $attributes->[1]->{code}, 'DeleteBorrowerAttribute deletes the correct entry');
190
$attr_0 = $borrower_attributes->next;
203
is( $borrower_attributes->[0]->{description}, $attribute_type2->description(), 'DeleteBorrowerAttribute deletes the correct entry');
191
is( $attr_0->code, $attributes->[1]->{code}, 'DeleteBorrowerAttribute deletes the correct entry');
204
is( $borrower_attributes->[0]->{value}, $attributes->[1]->{value}, 'DeleteBorrowerAttribute deletes the correct entry');
192
is( $attr_0->type->description, $attribute_type2->description(), 'DeleteBorrowerAttribute deletes the correct entry');
193
is( $attr_0->attribute, $attributes->[1]->{value}, 'DeleteBorrowerAttribute deletes the correct entry');
205
194
206
C4::Members::Attributes::DeleteBorrowerAttribute($borrowernumber, $attributes->[1]);
195
C4::Members::Attributes::DeleteBorrowerAttribute($borrowernumber, $attributes->[1]);
207
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
196
$borrower_attributes = $patron->get_extended_attributes;
208
is( @$borrower_attributes, 1, 'DeleteBorrowerAttribute deletes a borrower attribute' );
197
is( $borrower_attributes->count, 1, 'DeleteBorrowerAttribute deletes a borrower attribute' );
209
198
210
# Regression tests for bug 16504
199
# Regression tests for bug 16504
211
t::lib::Mocks::mock_userenv({ branchcode => $new_library->{branchcode} });
200
t::lib::Mocks::mock_userenv({ branchcode => $new_library->{branchcode} });
212
my $another_patron = $builder->build(
201
my $another_patron = $builder->build_object(
213
    {   source => 'Borrower',
202
    {   class  => 'Koha::Patrons',
214
        value  => {
203
        value  => {
215
            firstname    => 'my another firstname',
204
            firstname    => 'my another firstname',
216
            surname      => 'my another surname',
205
            surname      => 'my another surname',
Lines 232-239 $attributes = [ Link Here
232
        code => $attribute_type_limited->code(),
221
        code => $attribute_type_limited->code(),
233
    }
222
    }
234
];
223
];
235
C4::Members::Attributes::SetBorrowerAttributes($another_patron->{borrowernumber}, $attributes);
224
C4::Members::Attributes::SetBorrowerAttributes($another_patron->borrowernumber, $attributes);
236
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($another_patron->{borrowernumber});
225
$borrower_attributes = $another_patron->get_extended_attributes;
237
is( @$borrower_attributes, 3, 'SetBorrowerAttributes should have added the 3 attributes for another patron');
226
is( $borrower_attributes->count, 3, 'SetBorrowerAttributes should have added the 3 attributes for another patron');
238
$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
227
$borrower_attributes = $patron->get_extended_attributes;
239
is( @$borrower_attributes, 1, 'SetBorrowerAttributes should not have removed the attributes of other patrons' );
228
is( $borrower_attributes->count, 1, 'SetBorrowerAttributes should not have removed the attributes of other patrons' );
(-)a/tools/modborrowers.pl (-14 / +16 lines)
Lines 92-102 if ( $op eq 'show' ) { Link Here
92
        my $patron = Koha::Patrons->find( { cardnumber => $cardnumber } );
92
        my $patron = Koha::Patrons->find( { cardnumber => $cardnumber } );
93
        if ( $patron ) {
93
        if ( $patron ) {
94
            if ( $logged_in_user->can_see_patron_infos( $patron ) ) {
94
            if ( $logged_in_user->can_see_patron_infos( $patron ) ) {
95
                $patron = $patron->unblessed;
95
                my $borrower = $patron->unblessed;
96
                $patron->{patron_attributes} = C4::Members::Attributes::GetBorrowerAttributes( $patron->{borrowernumber} );
96
                my $attributes = $patron->get_extended_attributes;
97
                $max_nb_attr = scalar( @{ $patron->{patron_attributes} } )
97
                $borrower->{patron_attributes} = $attributes->as_list;
98
                    if scalar( @{ $patron->{patron_attributes} } ) > $max_nb_attr;
98
                $borrower->{patron_attributes_count} = $attributes->count;
99
                push @borrowers, $patron;
99
                $max_nb_attr = $borrower->{patron_attributes_count} if $borrower->{patron_attributes_count} > $max_nb_attr;
100
                push @borrowers, $borrower;
100
            } else {
101
            } else {
101
                push @notfoundcardnumbers, $cardnumber;
102
                push @notfoundcardnumbers, $cardnumber;
102
            }
103
            }
Lines 107-113 if ( $op eq 'show' ) { Link Here
107
108
108
    # Just for a correct display
109
    # Just for a correct display
109
    for my $borrower ( @borrowers ) {
110
    for my $borrower ( @borrowers ) {
110
        my $length = scalar( @{ $borrower->{patron_attributes} } );
111
        my $length = $borrower->{patron_attributes_count};
111
        push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
112
        push @{ $borrower->{patron_attributes} }, {} for ( $length .. $max_nb_attr - 1);
112
    }
113
    }
113
114
Lines 373-379 if ( $op eq 'do' ) { Link Here
373
            }
374
            }
374
        }
375
        }
375
376
376
        my $borrower_categorycode = Koha::Patrons->find( $borrowernumber )->categorycode;
377
        my $patron = Koha::Patrons->find( $borrowernumber );
377
        my $i=0;
378
        my $i=0;
378
        for ( @attributes ) {
379
        for ( @attributes ) {
379
            next unless $_;
380
            next unless $_;
Lines 382-388 if ( $op eq 'do' ) { Link Here
382
            $attribute->{attribute} = $attr_values[$i];
383
            $attribute->{attribute} = $attr_values[$i];
383
            my $attr_type = C4::Members::AttributeTypes->fetch( $_ );
384
            my $attr_type = C4::Members::AttributeTypes->fetch( $_ );
384
            # If this borrower is not in the category of this attribute, we don't want to modify this attribute
385
            # If this borrower is not in the category of this attribute, we don't want to modify this attribute
385
            ++$i and next if $attr_type->{category_code} and $attr_type->{category_code} ne $borrower_categorycode;
386
            ++$i and next if $attr_type->{category_code} and $attr_type->{category_code} ne $patron->category_code;
386
            my $valuename = "attr" . $i . "_value";
387
            my $valuename = "attr" . $i . "_value";
387
            if ( grep { $_ eq $valuename } @disabled ) {
388
            if ( grep { $_ eq $valuename } @disabled ) {
388
                # The attribute is disabled, we remove it for this borrower !
389
                # The attribute is disabled, we remove it for this borrower !
Lines 407-417 if ( $op eq 'do' ) { Link Here
407
    for my $borrowernumber ( @borrowernumbers ) {
408
    for my $borrowernumber ( @borrowernumbers ) {
408
        my $patron = Koha::Patrons->find( $borrowernumber );
409
        my $patron = Koha::Patrons->find( $borrowernumber );
409
        if ( $patron ) {
410
        if ( $patron ) {
410
            $patron = $patron->unblessed;
411
            my $category_description = $patron->category->description;
411
            $patron->{patron_attributes} = C4::Members::Attributes::GetBorrowerAttributes( $patron->{borrowernumber} );
412
            my $borrower = $patron->unblessed;
412
            $max_nb_attr = scalar( @{ $patron->{patron_attributes} } )
413
            $borrower->{category_description} = $category_description;
413
                if scalar( @{ $patron->{patron_attributes} } ) > $max_nb_attr;
414
            my $attributes = $patron->get_extended_attributes;
414
            push @borrowers, $patron;
415
            $borrower->{patron_attributes} = $attributes->as_list;
416
            $max_nb_attr = $attributes->count if $attributes->count > $max_nb_attr;
417
            push @borrowers, $borrower;
415
        }
418
        }
416
    }
419
    }
417
    my @patron_attributes_option;
420
    my @patron_attributes_option;
418
- 

Return to bug 20443