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

(-)a/C4/Auth_with_ldap.pm (-1 / +5 lines)
Lines 239-245 sub checkpw_ldap { Link Here
239
                next;
239
                next;
240
            }
240
            }
241
            if (C4::Members::Attributes::CheckUniqueness($code, $borrower{$code}, $borrowernumber)) {
241
            if (C4::Members::Attributes::CheckUniqueness($code, $borrower{$code}, $borrowernumber)) {
242
                C4::Members::Attributes::UpdateBorrowerAttribute($borrowernumber, {code => $code, attribute => $borrower{$code}});
242
                my $patron = Koha::Patrons->find($borrowernumber);
243
                if ( $patron ) { # Should not be needed, but we are in C4::Auth LDAP...
244
                    my $attribute = Koha::Patron::Attribute->new({code => $code, attribute => $borrower{$code}});
245
                    $patron->extended_attributes([$attribute]);
246
                }
243
            } else {
247
            } else {
244
                warn "ERROR_extended_unique_id_failed $code $borrower{$code}";
248
                warn "ERROR_extended_unique_id_failed $code $borrower{$code}";
245
            }
249
            }
(-)a/C4/ILSDI/Services.pm (-1 / +1 lines)
Lines 506-512 sub GetPatronInfo { Link Here
506
    if ( $show_attributes && $show_attributes eq "1" ) {
506
    if ( $show_attributes && $show_attributes eq "1" ) {
507
        # FIXME Regression expected here, we do not retrieve the same field as previously
507
        # FIXME Regression expected here, we do not retrieve the same field as previously
508
        # Waiting for answer on bug 14257 comment 15
508
        # Waiting for answer on bug 14257 comment 15
509
        my $attrs = $patron->get_extended_attributes->search({ opac_display => 1 })->unblessed;
509
        my $attrs = $patron->extended_attributes->search({ opac_display => 1 })->unblessed;
510
        $borrower->{'attributes'} = $attrs;
510
        $borrower->{'attributes'} = $attrs;
511
    }
511
    }
512
512
(-)a/C4/Letters.pm (-1 / +1 lines)
Lines 853-859 sub _parseletter { Link Here
853
    if ($table eq 'borrowers' && $letter->{content}) {
853
    if ($table eq 'borrowers' && $letter->{content}) {
854
        my $patron = Koha::Patrons->find( $values->{borrowernumber} );
854
        my $patron = Koha::Patrons->find( $values->{borrowernumber} );
855
        if ( $patron ) {
855
        if ( $patron ) {
856
            my $attributes = $patron->get_extended_attributes;
856
            my $attributes = $patron->extended_attributes;
857
            my %attr;
857
            my %attr;
858
            while ( my $attribute = $attributes->next ) {
858
            while ( my $attribute = $attributes->next ) {
859
                my $code = $attribute->code;
859
                my $code = $attribute->code;
(-)a/C4/Members.pm (-1 / +1 lines)
Lines 33-39 use C4::Reserves; Link Here
33
use C4::Accounts;
33
use C4::Accounts;
34
use C4::Biblio;
34
use C4::Biblio;
35
use C4::Letters;
35
use C4::Letters;
36
use C4::Members::Attributes qw(SearchIdMatchingAttribute UpdateBorrowerAttribute);
36
use C4::Members::Attributes qw(SearchIdMatchingAttribute);
37
use C4::NewsChannels; #get slip news
37
use C4::NewsChannels; #get slip news
38
use DateTime;
38
use DateTime;
39
use Koha::Database;
39
use Koha::Database;
(-)a/C4/Members/Attributes.pm (-62 / +4 lines)
Lines 29-36 our ($csv, $AttributeTypes); Link Here
29
29
30
BEGIN {
30
BEGIN {
31
    @ISA = qw(Exporter);
31
    @ISA = qw(Exporter);
32
    @EXPORT_OK = qw(CheckUniqueness SetBorrowerAttributes
32
    @EXPORT_OK = qw(CheckUniqueness
33
                    UpdateBorrowerAttribute
34
                    extended_attributes_code_value_arrayref extended_attributes_merge
33
                    extended_attributes_code_value_arrayref extended_attributes_merge
35
                    SearchIdMatchingAttribute);
34
                    SearchIdMatchingAttribute);
36
    %EXPORT_TAGS = ( all => \@EXPORT_OK );
35
    %EXPORT_TAGS = ( all => \@EXPORT_OK );
Lines 112-182 sub CheckUniqueness { Link Here
112
    return ($count == 0);
111
    return ($count == 0);
113
}
112
}
114
113
115
=head2 SetBorrowerAttributes 
116
117
  SetBorrowerAttributes($borrowernumber, [ { code => 'CODE', value => 'value' }, ... ] );
118
119
Set patron attributes for the patron identified by C<$borrowernumber>,
120
replacing any that existed previously.
121
122
=cut
123
124
sub SetBorrowerAttributes {
125
    my $borrowernumber = shift;
126
    my $attr_list = shift;
127
    my $no_branch_limit = shift // 0;
128
129
    my $dbh = C4::Context->dbh;
130
131
    my $attributes = Koha::Patrons->find($borrowernumber)->get_extended_attributes;
132
133
    unless ( $no_branch_limit ) {
134
        $attributes = $attributes->filter_by_branch_limitations;
135
    }
136
    $attributes->delete;
137
138
    my $sth = $dbh->prepare("INSERT INTO borrower_attributes (borrowernumber, code, attribute)
139
                             VALUES (?, ?, ?)");
140
    foreach my $attr (@$attr_list) {
141
        $sth->execute($borrowernumber, $attr->{code}, $attr->{value});
142
        if ($sth->err) {
143
            warn sprintf('Database returned the following error: %s', $sth->errstr);
144
            return; # bail immediately on errors
145
        }
146
    }
147
    return 1; # borrower attributes successfully set
148
}
149
150
=head2 UpdateBorrowerAttribute
151
152
  UpdateBorrowerAttribute($borrowernumber, $attribute );
153
154
Update a borrower attribute C<$attribute> for the patron identified by C<$borrowernumber>,
155
156
=cut
157
158
sub UpdateBorrowerAttribute {
159
    my ( $borrowernumber, $attribute ) = @_;
160
161
    Koha::Patrons->find($borrowernumber)->get_extended_attributes->search({ 'me.code' => $attribute->{code} })->filter_by_branch_limitations->delete;
162
163
    my $dbh = C4::Context->dbh;
164
    my $query = "INSERT INTO borrower_attributes SET attribute = ?, code = ?, borrowernumber = ?";
165
    my @params = ( $attribute->{attribute}, $attribute->{code}, $borrowernumber );
166
    my $sth = $dbh->prepare( $query );
167
168
    $sth->execute( @params );
169
}
170
171
172
=head2 extended_attributes_code_value_arrayref 
114
=head2 extended_attributes_code_value_arrayref 
173
115
174
   my $patron_attributes = "homeroom:1150605,grade:01,extradata:foobar";
116
   my $patron_attributes = "homeroom:1150605,grade:01,extradata:foobar";
175
   my $aref = extended_attributes_code_value_arrayref($patron_attributes);
117
   my $aref = extended_attributes_code_value_arrayref($patron_attributes);
176
118
177
Takes a comma-delimited CSV-style string argument and returns the kind of data structure that SetBorrowerAttributes wants, 
119
Takes a comma-delimited CSV-style string argument and returns the kind of data structure that Koha::Patron->extended_attributes wants,
178
namely a reference to array of hashrefs like:
120
namely a reference to array of hashrefs like:
179
 [ { code => 'CODE', value => 'value' }, { code => 'CODE2', value => 'othervalue' } ... ]
121
 [ { code => 'CODE', attribute => 'value' }, { code => 'CODE2', attribute => 'othervalue' } ... ]
180
122
181
Caches Text::CSV parser object for efficiency.
123
Caches Text::CSV parser object for efficiency.
182
124
Lines 190-196 sub extended_attributes_code_value_arrayref { Link Here
190
    # TODO: error handling (check $ok)
132
    # TODO: error handling (check $ok)
191
    return [
133
    return [
192
        sort {&_sort_by_code($a,$b)}
134
        sort {&_sort_by_code($a,$b)}
193
        map { map { my @arr = split /:/, $_, 2; { code => $arr[0], value => $arr[1] } } $_ }
135
        map { map { my @arr = split /:/, $_, 2; { code => $arr[0], attribute => $arr[1] } } $_ }
194
        @list
136
        @list
195
    ];
137
    ];
196
    # nested map because of split
138
    # nested map because of split
(-)a/Koha/Patron.pm (-4 / +29 lines)
Lines 1438-1453 sub generate_userid { Link Here
1438
     return $self;
1438
     return $self;
1439
}
1439
}
1440
1440
1441
=head3 get_extended_attributes
1441
=head3 add_extended_attribute
1442
1442
1443
my $attributes = $patron->get_extended_attributes
1443
=cut
1444
1445
sub add_extended_attribute {
1446
    my ($self, $attribute) = @_;
1447
    $attribute->{borrowernumber} = $self->borrowernumber;
1448
    return Koha::Patron::Attribute->new($attribute)->store;
1449
}
1450
1451
=head3 extended_attributes
1444
1452
1445
Return object of Koha::Patron::Attributes type with all attributes set for this patron
1453
Return object of Koha::Patron::Attributes type with all attributes set for this patron
1446
1454
1455
Or setter FIXME
1456
1447
=cut
1457
=cut
1448
1458
1449
sub get_extended_attributes {
1459
sub extended_attributes {
1450
    my ( $self ) = @_;
1460
    my ( $self, $attributes ) = @_;
1461
    if ($attributes) {    # setter
1462
        my $schema = $self->_result->result_source->schema;
1463
        $schema->txn_do(
1464
            sub {
1465
                # Remove the existing one
1466
                $self->extended_attributes->filter_by_branch_limitations->delete;
1467
1468
                # Insert the new ones
1469
                for my $attribute (@$attributes) {
1470
                    $self->_result->create_related('borrower_attributes', $attribute);
1471
                }
1472
            }
1473
        );
1474
    }
1475
1451
    my $rs = $self->_result->borrower_attributes;
1476
    my $rs = $self->_result->borrower_attributes;
1452
    # We call search to use the filters in Koha::Patron::Attributes->search
1477
    # We call search to use the filters in Koha::Patron::Attributes->search
1453
    return Koha::Patron::Attributes->_new_from_dbic($rs)->search;
1478
    return Koha::Patron::Attributes->_new_from_dbic($rs)->search;
(-)a/Koha/Patrons/Import.pm (-5 / +14 lines)
Lines 290-300 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 = $patron->get_extended_attributes->as_list;
293
                    my $old_attributes = $patron->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
                eval {
297
                  unless SetBorrowerAttributes( $borrower{'borrowernumber'}, $patron_attributes, 'no_branch_limit' );
297
                    # We do not want to filter by branch, maybe we should?
298
                    Koha::Patrons->find($borrowernumber)->extended_attributes->delete;
299
                    $patron->extended_attributes($patron_attributes);
300
                };
301
                if ($@) {
302
                    # FIXME This is not an unknown error, we can do better here
303
                    push @errors, { unknown_error => 1 };
304
                }
298
            }
305
            }
299
            $overwritten++;
306
            $overwritten++;
300
            push(
307
            push(
Lines 323-329 sub import_patrons { Link Here
323
                }
330
                }
324
331
325
                if ($extended) {
332
                if ($extended) {
326
                    SetBorrowerAttributes( $patron->borrowernumber, $patron_attributes );
333
                    # FIXME Hum, we did not filter earlier and now we do?
334
                    $patron->extended_attributes->filter_by_branch_limitations->delete;
335
                    $patron->extended_attributes($patron_attributes);
327
                }
336
                }
328
337
329
                if ($set_messaging_prefs) {
338
                if ($set_messaging_prefs) {
Lines 451-457 sub set_column_keys { Link Here
451
460
452
 my $patron_attributes = set_patron_attributes($extended, $borrower{patron_attributes}, $feedback);
461
 my $patron_attributes = set_patron_attributes($extended, $borrower{patron_attributes}, $feedback);
453
462
454
Returns a reference to array of hashrefs data structure as expected by SetBorrowerAttributes.
463
Returns a reference to array of hashrefs data structure as expected by Koha::Patron->extended_attributes
455
464
456
=cut
465
=cut
457
466
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc (-1 / +1 lines)
Lines 71-77 Link Here
71
    [% END %]
71
    [% END %]
72
72
73
    [% IF Koha.Preference('ExtendedPatronAttributes') %]
73
    [% IF Koha.Preference('ExtendedPatronAttributes') %]
74
        [% FOREACH extendedattribute IN patron.get_extended_attributes %]
74
        [% FOREACH extendedattribute IN patron.extended_attributes %]
75
            [% IF ( extendedattribute.type.display_checkout ) %] [%# FIXME We should filter in the line above %]
75
            [% IF ( extendedattribute.type.display_checkout ) %] [%# FIXME We should filter in the line above %]
76
                [% IF ( extendedattribute.attribute ) %] [%# FIXME Why that? why not if == 0? %]
76
                [% IF ( extendedattribute.attribute ) %] [%# FIXME Why that? why not if == 0? %]
77
                    <li class="patronattribute">
77
                    <li class="patronattribute">
(-)a/members/memberentry.pl (-3 / +5 lines)
Lines 480-486 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
480
        }
480
        }
481
481
482
        if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) {
482
        if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) {
483
            C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes);
483
            $patron->extended_attributes->filter_by_branch_limitations->delete;
484
            $patron->extended_attributes($extended_patron_attributes);
484
        }
485
        }
485
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
486
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
486
            C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template, 1, $newdata{'categorycode'});
487
            C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template, 1, $newdata{'categorycode'});
Lines 550-556 if ((!$nok) and $nodouble and ($op eq 'insert' or $op eq 'save')){ Link Here
550
551
551
        add_guarantors( $patron, $input );
552
        add_guarantors( $patron, $input );
552
        if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) {
553
        if (C4::Context->preference('ExtendedPatronAttributes') and $input->param('setting_extended_patron_attributes')) {
553
            C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $extended_patron_attributes);
554
            $patron->extended_attributes->filter_by_branch_limitations->delete;
555
            $patron->extended_attributes($extended_patron_attributes);
554
        }
556
        }
555
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
557
        if (C4::Context->preference('EnhancedMessagingPreferences') and $input->param('setting_messaging_prefs')) {
556
            C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template);
558
            C4::Form::MessagingPreferences::handle_form_action($input, { borrowernumber => $borrowernumber }, $template);
Lines 858-864 sub patron_attributes_form { Link Here
858
        return;
860
        return;
859
    }
861
    }
860
    my $patron = Koha::Patrons->find($borrowernumber); # Already fetched but outside of this sub
862
    my $patron = Koha::Patrons->find($borrowernumber); # Already fetched but outside of this sub
861
    my @attributes = $patron->get_extended_attributes->as_list; # FIXME Must be improved!
863
    my @attributes = $patron->extended_attributes->as_list; # FIXME Must be improved!
862
    my @classes = uniq( map {$_->type->class} @attributes );
864
    my @classes = uniq( map {$_->type->class} @attributes );
863
    @classes = sort @classes;
865
    @classes = sort @classes;
864
866
(-)a/members/moremember.pl (-1 / +1 lines)
Lines 130-136 $template->param( Link Here
130
);
130
);
131
131
132
if (C4::Context->preference('ExtendedPatronAttributes')) {
132
if (C4::Context->preference('ExtendedPatronAttributes')) {
133
    my @attributes = $patron->get_extended_attributes->as_list; # FIXME Must be improved!
133
    my @attributes = $patron->extended_attributes->as_list; # FIXME Must be improved!
134
    my @classes = uniq( map {$_->type->class} @attributes );
134
    my @classes = uniq( map {$_->type->class} @attributes );
135
    @classes = sort @classes;
135
    @classes = sort @classes;
136
136
(-)a/opac/opac-memberentry.pl (-1 / +2 lines)
Lines 213-219 if ( $action eq 'create' ) { Link Here
213
            my $patron = Koha::Patron->new( \%borrower )->store;
213
            my $patron = Koha::Patron->new( \%borrower )->store;
214
            Koha::Patron::Consent->new({ borrowernumber => $patron->borrowernumber, type => 'GDPR_PROCESSING', given_on => $consent_dt })->store if $consent_dt;
214
            Koha::Patron::Consent->new({ borrowernumber => $patron->borrowernumber, type => 'GDPR_PROCESSING', given_on => $consent_dt })->store if $consent_dt;
215
            if ( $patron ) {
215
            if ( $patron ) {
216
                C4::Members::Attributes::SetBorrowerAttributes( $patron->borrowernumber, $attributes );
216
                $patron->extended_attributes->filter_by_branch_limitations->delete;
217
                $patron->extended_attributes($attributes);
217
                if ( C4::Context->preference('EnhancedMessagingPreferences') ) {
218
                if ( C4::Context->preference('EnhancedMessagingPreferences') ) {
218
                    C4::Form::MessagingPreferences::handle_form_action(
219
                    C4::Form::MessagingPreferences::handle_form_action(
219
                        $cgi,
220
                        $cgi,
(-)a/t/db_dependent/Auth_with_ldap.t (-1 / +1 lines)
Lines 206-212 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
            Koha::Patrons->find($borrower->{borrowernumber})->get_extended_attributes->count,
209
            Koha::Patrons->find($borrower->{borrowernumber})->extended_attributes->count,
210
            'Extended attributes are not deleted'
210
            'Extended attributes are not deleted'
211
        );
211
        );
212
212
(-)a/t/db_dependent/Koha/Patron/Modifications.t (-1 / +1 lines)
Lines 174-180 subtest 'approve tests' => sub { Link Here
174
    );
174
    );
175
    is( $patron->firstname, 'Kyle',
175
    is( $patron->firstname, 'Kyle',
176
        'Patron modification set the right firstname' );
176
        'Patron modification set the right firstname' );
177
    my $patron_attributes = $patron->get_extended_attributes;
177
    my $patron_attributes = $patron->extended_attributes;
178
    my $attribute_1 = $patron_attributes->next;
178
    my $attribute_1 = $patron_attributes->next;
179
    is( $attribute_1->code,
179
    is( $attribute_1->code,
180
        'CODE_1', 'Patron modification correctly saved attribute code' );
180
        'CODE_1', 'Patron modification correctly saved attribute code' );
(-)a/t/db_dependent/Koha/Patrons.t (-9 / +11 lines)
Lines 2019-2025 subtest 'anonymize' => sub { Link Here
2019
};
2019
};
2020
$schema->storage->txn_rollback;
2020
$schema->storage->txn_rollback;
2021
2021
2022
subtest 'get_extended_attributes' => sub {
2022
subtest 'extended_attributes' => sub {
2023
    plan tests => 10;
2023
    plan tests => 10;
2024
    my $schema = Koha::Database->new->schema;
2024
    my $schema = Koha::Database->new->schema;
2025
    $schema->storage->txn_begin;
2025
    $schema->storage->txn_begin;
Lines 2069-2085 subtest 'get_extended_attributes' => sub { Link Here
2069
        }
2069
        }
2070
    ];
2070
    ];
2071
2071
2072
    my $extended_attributes = $patron_1->get_extended_attributes;
2072
    my $extended_attributes = $patron_1->extended_attributes;
2073
    is( ref($extended_attributes), 'Koha::Patron::Attributes', 'Koha::Patron->get_extended_attributes must return a Koha::Patron::Attribute set' );
2073
    is( ref($extended_attributes), 'Koha::Patron::Attributes', 'Koha::Patron->extended_attributes must return a Koha::Patron::Attribute set' );
2074
    is( $extended_attributes->count, 0, 'There should not be attribute yet');
2074
    is( $extended_attributes->count, 0, 'There should not be attribute yet');
2075
2075
2076
    C4::Members::Attributes::SetBorrowerAttributes($patron_1->borrowernumber, $attributes_for_1);
2076
    $patron_1->extended_attributes->filter_by_branch_limitations->delete;
2077
    C4::Members::Attributes::SetBorrowerAttributes($patron_2->borrowernumber, $attributes_for_2);
2077
    $patron_2->extended_attributes->filter_by_branch_limitations->delete;
2078
    $patron_1->extended_attributes($attributes_for_1);
2079
    $patron_2->extended_attributes($attributes_for_2);
2078
2080
2079
    my $extended_attributes_for_1 = $patron_1->get_extended_attributes;
2081
    my $extended_attributes_for_1 = $patron_1->extended_attributes;
2080
    is( $extended_attributes_for_1->count, 3, 'There should be 3 attributes now for patron 1');
2082
    is( $extended_attributes_for_1->count, 3, 'There should be 3 attributes now for patron 1');
2081
2083
2082
    my $extended_attributes_for_2 = $patron_2->get_extended_attributes;
2084
    my $extended_attributes_for_2 = $patron_2->extended_attributes;
2083
    is( $extended_attributes_for_2->count, 2, 'There should be 2 attributes now for patron 2');
2085
    is( $extended_attributes_for_2->count, 2, 'There should be 2 attributes now for patron 2');
2084
2086
2085
    my $attribute_12 = $extended_attributes_for_2->search({ code => $attribute_type1->code });
2087
    my $attribute_12 = $extended_attributes_for_2->search({ code => $attribute_type1->code });
Lines 2095-2105 subtest 'get_extended_attributes' => sub { Link Here
2095
    # Test branch limitations
2097
    # Test branch limitations
2096
    set_logged_in_user($patron_2);
2098
    set_logged_in_user($patron_2);
2097
    # Return all
2099
    # Return all
2098
    $extended_attributes_for_1 = $patron_1->get_extended_attributes;
2100
    $extended_attributes_for_1 = $patron_1->extended_attributes;
2099
    is( $extended_attributes_for_1->count, 3, 'There should be 2 attributes for patron 1, the limited one should be returned');
2101
    is( $extended_attributes_for_1->count, 3, 'There should be 2 attributes for patron 1, the limited one should be returned');
2100
2102
2101
    # Return filtered
2103
    # Return filtered
2102
    $extended_attributes_for_1 = $patron_1->get_extended_attributes->filter_by_branch_limitations;
2104
    $extended_attributes_for_1 = $patron_1->extended_attributes->filter_by_branch_limitations;
2103
    is( $extended_attributes_for_1->count, 2, 'There should be 2 attributes for patron 1, the limited one should be returned');
2105
    is( $extended_attributes_for_1->count, 2, 'There should be 2 attributes for patron 1, the limited one should be returned');
2104
2106
2105
    # Not filtered
2107
    # Not filtered
(-)a/t/db_dependent/Koha/Patrons/Import.t (-2 / +2 lines)
Lines 562-571 subtest 'test_set_patron_attributes' => sub { Link Here
562
    # Then ...
562
    # Then ...
563
    ok($result_3, 'Got some data back from set patron attributes');
563
    ok($result_3, 'Got some data back from set patron attributes');
564
    is($result_3->[0]->{code}, 'grade', 'Got the expected first code from set patron attributes');
564
    is($result_3->[0]->{code}, 'grade', 'Got the expected first code from set patron attributes');
565
    is($result_3->[0]->{value}, '01', 'Got the expected first value from set patron attributes');
565
    is($result_3->[0]->{attribute}, '01', 'Got the expected first value from set patron attributes');
566
566
567
    is($result_3->[1]->{code}, 'homeroom', 'Got the expected second code from set patron attributes');
567
    is($result_3->[1]->{code}, 'homeroom', 'Got the expected second code from set patron attributes');
568
    is($result_3->[1]->{value}, 1150605, 'Got the expected second value from set patron attributes');
568
    is($result_3->[1]->{attribute}, 1150605, 'Got the expected second value from set patron attributes');
569
569
570
    is(scalar @feedback_3, 1, 'Got the expected 1 array size from set patron attributes with extended user');
570
    is(scalar @feedback_3, 1, 'Got the expected 1 array size from set patron attributes with extended user');
571
    is($feedback_3[0]->{feedback}, 1, 'Got the expected second feedback from set patron attributes with extended user');
571
    is($feedback_3[0]->{feedback}, 1, 'Got the expected second feedback from set patron attributes with extended user');
(-)a/t/db_dependent/Members/Attributes.t (-43 / +49 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 => 38;
29
use Test::More tests => 39;
30
30
31
use_ok('C4::Members::Attributes');
31
use_ok('C4::Members::Attributes');
32
32
Lines 71-149 $attribute_type_limited->branches([ $new_library->{branchcode} ]); Link Here
71
$attribute_type_limited->store;
71
$attribute_type_limited->store;
72
72
73
$patron = Koha::Patrons->find($borrowernumber);
73
$patron = Koha::Patrons->find($borrowernumber);
74
my $borrower_attributes = $patron->get_extended_attributes;
74
my $borrower_attributes = $patron->extended_attributes;
75
is( $borrower_attributes->count, 0, 'get_extended_attributes returns the correct number of borrower attributes' );
75
is( $borrower_attributes->count, 0, 'extended_attributes returns the correct number of borrower attributes' );
76
76
77
my $attributes = [
77
my $attributes = [
78
    {
78
    {
79
        value => 'my attribute1',
79
        attribute => 'my attribute1',
80
        code => $attribute_type1->code(),
80
        code => $attribute_type1->code(),
81
    },
81
    },
82
    {
82
    {
83
        value => 'my attribute2',
83
        attribute => 'my attribute2',
84
        code => $attribute_type2->code(),
84
        code => $attribute_type2->code(),
85
    },
85
    },
86
    {
86
    {
87
        value => 'my attribute limited',
87
        attribute => 'my attribute limited',
88
        code => $attribute_type_limited->code(),
88
        code => $attribute_type_limited->code(),
89
    }
89
    }
90
];
90
];
91
91
92
my $set_borrower_attributes = C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $attributes);
92
$patron->extended_attributes->filter_by_branch_limitations->delete;
93
is( $set_borrower_attributes, 1, 'SetBorrowerAttributes returns the success code' );
93
my $set_borrower_attributes = $patron->extended_attributes($attributes);
94
$borrower_attributes = $patron->get_extended_attributes;
94
is( ref($set_borrower_attributes), 'Koha::Patron::Attributes', '');
95
is( $borrower_attributes->count, 3, 'get_extended_attributes returns the correct number of borrower attributes' );
95
is( $set_borrower_attributes->count, 3, '');
96
$borrower_attributes = $patron->extended_attributes;
97
is( $borrower_attributes->count, 3, 'extended_attributes returns the correct number of borrower attributes' );
96
my $attr_0 = $borrower_attributes->next;
98
my $attr_0 = $borrower_attributes->next;
97
is( $attr_0->code, $attributes->[0]->{code}, 'SetBorrowerAttributes stores the correct code correctly' );
99
is( $attr_0->code, $attributes->[0]->{code}, 'setter for extended_attributes sestores the correct code correctly' );
98
is( $attr_0->type->description, $attribute_type1->description(), 'SetBorrowerAttributes stores the field description correctly' );
100
is( $attr_0->type->description, $attribute_type1->description(), 'setter for extended_attributes stores the field description correctly' );
99
is( $attr_0->attribute, $attributes->[0]->{value}, 'SetBorrowerAttributes stores the field value correctly' );
101
is( $attr_0->attribute, $attributes->[0]->{attribute}, 'setter for extended_attributes stores the field value correctly' );
100
my $attr_1 = $borrower_attributes->next;
102
my $attr_1 = $borrower_attributes->next;
101
is( $attr_1->code, $attributes->[1]->{code}, 'SetBorrowerAttributes stores the field code correctly' );
103
is( $attr_1->code, $attributes->[1]->{code}, 'setter for extended_attributes stores the field code correctly' );
102
is( $attr_1->type->description, $attribute_type2->description(), 'SetBorrowerAttributes stores the field description correctly' );
104
is( $attr_1->type->description, $attribute_type2->description(), 'setter for extended_attributes stores the field description correctly' );
103
is( $attr_1->attribute, $attributes->[1]->{value}, 'SetBorrowerAttributes stores the field value correctly' );
105
is( $attr_1->attribute, $attributes->[1]->{attribute}, 'setter for extended_attributes stores the field value correctly' );
104
106
105
$attributes = [
107
$attributes = [
106
    {
108
    {
107
        value => 'my attribute1',
109
        attribute => 'my attribute1',
108
        code => $attribute_type1->code(),
110
        code => $attribute_type1->code(),
109
    },
111
    },
110
    {
112
    {
111
        value => 'my attribute2',
113
        attribute => 'my attribute2',
112
        code => $attribute_type2->code(),
114
        code => $attribute_type2->code(),
113
    }
115
    }
114
];
116
];
115
C4::Members::Attributes::SetBorrowerAttributes($borrowernumber, $attributes);
117
$patron->extended_attributes->filter_by_branch_limitations->delete;
116
$borrower_attributes = $patron->get_extended_attributes;
118
$patron->extended_attributes($attributes);
117
is( $borrower_attributes->count, 3, 'SetBorrowerAttributes should not have removed the attributes limited to another branch' );
119
$borrower_attributes = $patron->extended_attributes;
120
is( $borrower_attributes->count, 3, 'setter for extended_attributes should not have removed the attributes limited to another branch' );
118
121
119
# TODO This is not implemented yet
122
# TODO This is not implemented yet
120
#$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, undef, 'branch_limited');
123
#$borrower_attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, undef, 'branch_limited');
121
#is( @$borrower_attributes, 2, 'GetBorrowerAttributes returns the correct number of borrower attributes filtered on library' );
124
#is( @$borrower_attributes, 2, 'GetBorrowerAttributes returns the correct number of borrower attributes filtered on library' );
122
125
123
$patron = Koha::Patrons->find($borrowernumber);
126
$patron = Koha::Patrons->find($borrowernumber);
124
my $extended_attributes = $patron->get_extended_attributes;
127
my $extended_attributes = $patron->extended_attributes;
125
my $attribute_value = $extended_attributes->search({ code => 'my invalid code' });
128
my $attribute_value = $extended_attributes->search({ code => 'my invalid code' });
126
is( $attribute_value->count, 0, 'non existent attribute should return empty result set');
129
is( $attribute_value->count, 0, 'non existent attribute should return empty result set');
127
$attribute_value = $patron->get_extended_attribute('my invalid code');
130
$attribute_value = $patron->get_extended_attribute('my invalid code');
128
is( $attribute_value, undef, 'non existent attribute should undef');
131
is( $attribute_value, undef, 'non existent attribute should undef');
129
132
130
$attribute_value = $patron->get_extended_attribute($attributes->[0]->{code});
133
$attribute_value = $patron->get_extended_attribute($attributes->[0]->{code});
131
is( $attribute_value->attribute, $attributes->[0]->{value}, 'get_extended_attribute returns the correct attribute value' );
134
is( $attribute_value->attribute, $attributes->[0]->{attribute}, 'get_extended_attribute returns the correct attribute value' );
132
$attribute_value = $patron->get_extended_attribute($attributes->[1]->{code});
135
$attribute_value = $patron->get_extended_attribute($attributes->[1]->{code});
133
is( $attribute_value->attribute, $attributes->[1]->{value}, 'get_extended_attribute returns the correct attribute value' );
136
is( $attribute_value->attribute, $attributes->[1]->{attribute}, 'get_extended_attribute returns the correct attribute value' );
134
137
135
138
136
my $attribute = {
139
my $attribute = {
137
    attribute => 'my attribute3',
140
    attribute => 'my attribute3',
138
    code => $attribute_type1->code(),
141
    code => $attribute_type1->code(),
139
};
142
};
140
C4::Members::Attributes::UpdateBorrowerAttribute($borrowernumber, $attribute);
143
$patron->extended_attributes->search({'me.code' => $attribute->{code}})->filter_by_branch_limitations->delete;
141
$borrower_attributes = $patron->get_extended_attributes;
144
$patron->add_extended_attribute($attribute);
142
is( $borrower_attributes->count, 3, 'UpdateBorrowerAttribute does not change the number of borrower attributes' );
145
$borrower_attributes = $patron->extended_attributes;
146
is( $borrower_attributes->count, 3, 'delete then add a new attribute does not change the number of borrower attributes' );
143
$attr_0 = $borrower_attributes->next;
147
$attr_0 = $borrower_attributes->next;
144
is( $attr_0->code, $attribute->{code}, 'UpdateBorrowerAttribute updates the field code correctly' );
148
is( $attr_0->code, $attribute->{code}, 'delete then add a new attribute updates the field code correctly' );
145
is( $attr_0->type->description, $attribute_type1->description(), 'UpdateBorrowerAttribute updates the field description correctly' );
149
is( $attr_0->type->description, $attribute_type1->description(), 'delete then add a new attribute updates the field description correctly' );
146
is( $attr_0->attribute, $attribute->{attribute}, 'UpdateBorrowerAttribute updates the field value correctly' );
150
is( $attr_0->attribute, $attribute->{attribute}, 'delete then add a new attribute updates the field value correctly' );
147
151
148
152
149
my $check_uniqueness = C4::Members::Attributes::CheckUniqueness();
153
my $check_uniqueness = C4::Members::Attributes::CheckUniqueness();
Lines 160-166 $check_uniqueness = C4::Members::Attributes::CheckUniqueness($attribute->{code}, Link Here
160
is( $check_uniqueness, 1, 'CheckUniqueness with a new value returns true' );
164
is( $check_uniqueness, 1, 'CheckUniqueness with a new value returns true' );
161
$check_uniqueness = C4::Members::Attributes::CheckUniqueness('my invalid code', 'new value');
165
$check_uniqueness = C4::Members::Attributes::CheckUniqueness('my invalid code', 'new value');
162
is( $check_uniqueness, 0, 'CheckUniqueness with an invalid argument code and a new value returns false' );
166
is( $check_uniqueness, 0, 'CheckUniqueness with an invalid argument code and a new value returns false' );
163
$check_uniqueness = C4::Members::Attributes::CheckUniqueness($attributes->[1]->{code}, $attributes->[1]->{value});
167
$check_uniqueness = C4::Members::Attributes::CheckUniqueness($attributes->[1]->{code}, $attributes->[1]->{attribute});
164
is( $check_uniqueness, 1, 'CheckUniqueness with an attribute unique_id=0 returns true' );
168
is( $check_uniqueness, 1, 'CheckUniqueness with an attribute unique_id=0 returns true' );
165
$check_uniqueness = C4::Members::Attributes::CheckUniqueness($attribute->{code}, $attribute->{attribute});
169
$check_uniqueness = C4::Members::Attributes::CheckUniqueness($attribute->{code}, $attribute->{attribute});
166
is( $check_uniqueness, '', 'CheckUniqueness returns false' );
170
is( $check_uniqueness, '', 'CheckUniqueness returns false' );
Lines 168-189 is( $check_uniqueness, '', 'CheckUniqueness returns false' ); Link Here
168
172
169
my $borrower_numbers = C4::Members::Attributes::SearchIdMatchingAttribute('attribute1');
173
my $borrower_numbers = C4::Members::Attributes::SearchIdMatchingAttribute('attribute1');
170
is( @$borrower_numbers, 0, 'SearchIdMatchingAttribute searchs only in attributes with staff_searchable=1' );
174
is( @$borrower_numbers, 0, 'SearchIdMatchingAttribute searchs only in attributes with staff_searchable=1' );
171
for my $attr( split(' ', $attributes->[1]->{value}) ) {
175
for my $attr( split(' ', $attributes->[1]->{attribute}) ) {
172
    $borrower_numbers = C4::Members::Attributes::SearchIdMatchingAttribute($attr);
176
    $borrower_numbers = C4::Members::Attributes::SearchIdMatchingAttribute($attr);
173
    is( $borrower_numbers->[0], $borrowernumber, 'SearchIdMatchingAttribute returns the borrower numbers matching' );
177
    is( $borrower_numbers->[0], $borrowernumber, 'SearchIdMatchingAttribute returns the borrower numbers matching' );
174
}
178
}
175
179
176
180
177
$patron->get_extended_attribute($attribute->{code})->delete;
181
$patron->get_extended_attribute($attribute->{code})->delete;
178
$borrower_attributes = $patron->get_extended_attributes;
182
$borrower_attributes = $patron->extended_attributes;
179
is( $borrower_attributes->count, 2, 'delete attribute by code' );
183
is( $borrower_attributes->count, 2, 'delete attribute by code' );
180
$attr_0 = $borrower_attributes->next;
184
$attr_0 = $borrower_attributes->next;
181
is( $attr_0->code, $attributes->[1]->{code}, 'delete attribute by code');
185
is( $attr_0->code, $attributes->[1]->{code}, 'delete attribute by code');
182
is( $attr_0->type->description, $attribute_type2->description(), 'delete attribute by code');
186
is( $attr_0->type->description, $attribute_type2->description(), 'delete attribute by code');
183
is( $attr_0->attribute, $attributes->[1]->{value}, 'delete attribute by code');
187
is( $attr_0->attribute, $attributes->[1]->{attribute}, 'delete attribute by code');
184
188
185
$patron->get_extended_attribute($attributes->[1]->{code})->delete;
189
$patron->get_extended_attribute($attributes->[1]->{code})->delete;
186
$borrower_attributes = $patron->get_extended_attributes;
190
$borrower_attributes = $patron->extended_attributes;
187
is( $borrower_attributes->count, 1, 'delete attribute by code' );
191
is( $borrower_attributes->count, 1, 'delete attribute by code' );
188
192
189
# Regression tests for bug 16504
193
# Regression tests for bug 16504
Lines 199-218 my $another_patron = $builder->build_object( Link Here
199
);
203
);
200
$attributes = [
204
$attributes = [
201
    {
205
    {
202
        value => 'my attribute1',
206
        attribute => 'my attribute1',
203
        code => $attribute_type1->code(),
207
        code => $attribute_type1->code(),
204
    },
208
    },
205
    {
209
    {
206
        value => 'my attribute2',
210
        attribute => 'my attribute2',
207
        code => $attribute_type2->code(),
211
        code => $attribute_type2->code(),
208
    },
212
    },
209
    {
213
    {
210
        value => 'my attribute limited',
214
        attribute => 'my attribute limited',
211
        code => $attribute_type_limited->code(),
215
        code => $attribute_type_limited->code(),
212
    }
216
    }
213
];
217
];
214
C4::Members::Attributes::SetBorrowerAttributes($another_patron->borrowernumber, $attributes);
218
215
$borrower_attributes = $another_patron->get_extended_attributes;
219
$another_patron->extended_attributes->filter_by_branch_limitations->delete;
216
is( $borrower_attributes->count, 3, 'SetBorrowerAttributes should have added the 3 attributes for another patron');
220
$another_patron->extended_attributes($attributes);
217
$borrower_attributes = $patron->get_extended_attributes;
221
$borrower_attributes = $another_patron->extended_attributes;
218
is( $borrower_attributes->count, 1, 'SetBorrowerAttributes should not have removed the attributes of other patrons' );
222
is( $borrower_attributes->count, 3, 'setter for extended_attributes should have added the 3 attributes for another patron');
223
$borrower_attributes = $patron->extended_attributes;
224
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 (-7 / +22 lines)
Lines 26-31 use C4::Members::Attributes; Link Here
26
use C4::Members::AttributeTypes;
26
use C4::Members::AttributeTypes;
27
27
28
use Koha::Library;
28
use Koha::Library;
29
use Koha::Patrons;
29
use Koha::Patron::Categories;
30
use Koha::Patron::Categories;
30
31
31
use t::lib::Mocks;
32
use t::lib::Mocks;
Lines 279-293 my $attribute_type = C4::Members::AttributeTypes->new( 'ATM_1', 'my attribute ty Link Here
279
$attribute_type->{staff_searchable} = 1;
280
$attribute_type->{staff_searchable} = 1;
280
$attribute_type->store;
281
$attribute_type->store;
281
282
282
283
Koha::Patrons->find( $john_doe->{borrowernumber} )->extended_attributes(
283
C4::Members::Attributes::SetBorrowerAttributes(
284
    [
284
    $john_doe->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'the default value for a common user' } ]
285
        {
286
            code      => $attribute_type->{code},
287
            attribute => 'the default value for a common user'
288
        }
289
    ]
285
);
290
);
286
C4::Members::Attributes::SetBorrowerAttributes(
291
Koha::Patrons->find( $jane_doe->{borrowernumber} )->extended_attributes(
287
    $jane_doe->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'the default value for another common user' } ]
292
    [
293
        {
294
            code      => $attribute_type->{code},
295
            attribute => 'the default value for another common user'
296
        }
297
    ]
288
);
298
);
289
C4::Members::Attributes::SetBorrowerAttributes(
299
Koha::Patrons->find( $john_smith->{borrowernumber} )->extended_attributes(
290
    $john_smith->{borrowernumber}, [ { code => $attribute_type->{code}, value => 'Attribute which not appears even if contains "Dupont"' } ]
300
    [
301
        {
302
            code      => $attribute_type->{code},
303
            attribute => 'Attribute which not appears even if contains "Dupont"'
304
        }
305
    ]
291
);
306
);
292
307
293
t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 1);
308
t::lib::Mocks::mock_preference('ExtendedPatronAttributes', 1);
(-)a/tools/modborrowers.pl (-4 / +7 lines)
Lines 93-99 if ( $op eq 'show' ) { Link Here
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
                my $borrower = $patron->unblessed;
95
                my $borrower = $patron->unblessed;
96
                my $attributes = $patron->get_extended_attributes;
96
                my $attributes = $patron->extended_attributes;
97
                $borrower->{patron_attributes} = $attributes->as_list;
97
                $borrower->{patron_attributes} = $attributes->as_list;
98
                $borrower->{patron_attributes_count} = $attributes->count;
98
                $borrower->{patron_attributes_count} = $attributes->count;
99
                $max_nb_attr = $borrower->{patron_attributes_count} if $borrower->{patron_attributes_count} > $max_nb_attr;
99
                $max_nb_attr = $borrower->{patron_attributes_count} if $borrower->{patron_attributes_count} > $max_nb_attr;
Lines 393-399 if ( $op eq 'do' ) { Link Here
393
                push @errors, { error => $@ } if $@;
393
                push @errors, { error => $@ } if $@;
394
            } else {
394
            } else {
395
                eval {
395
                eval {
396
                    C4::Members::Attributes::UpdateBorrowerAttribute( $borrowernumber, $attribute );
396
                    # Note:
397
                    # We should not need to filter by branch, but stay on the safe side
398
                    # Repeatable are not supported so we can do that - TODO
399
                    $patron->extended_attributes->search({'me.code' => $attribute->{code}})->filter_by_branch_limitations->delete;
400
                    $patron->add_extended_attribute($attribute);
397
                };
401
                };
398
                push @errors, { error => $@ } if $@;
402
                push @errors, { error => $@ } if $@;
399
            }
403
            }
Lines 411-417 if ( $op eq 'do' ) { Link Here
411
            my $category_description = $patron->category->description;
415
            my $category_description = $patron->category->description;
412
            my $borrower = $patron->unblessed;
416
            my $borrower = $patron->unblessed;
413
            $borrower->{category_description} = $category_description;
417
            $borrower->{category_description} = $category_description;
414
            my $attributes = $patron->get_extended_attributes;
418
            my $attributes = $patron->extended_attributes;
415
            $borrower->{patron_attributes} = $attributes->as_list;
419
            $borrower->{patron_attributes} = $attributes->as_list;
416
            $max_nb_attr = $attributes->count if $attributes->count > $max_nb_attr;
420
            $max_nb_attr = $attributes->count if $attributes->count > $max_nb_attr;
417
            push @borrowers, $borrower;
421
            push @borrowers, $borrower;
418
- 

Return to bug 20443