diff --git a/Koha/Patron.pm b/Koha/Patron.pm index d6763fefe8..5a5dd215c7 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -3963,6 +3963,73 @@ sub create_expiry_notice_parameters { return $sending_params; } +=head3 identify_updated_extended_attributes + +Compares an array of updated extended attributes with the stored values to identify changes + +=cut + +sub identify_updated_extended_attributes { + my ( $self, $entered_attributes ) = @_; + + my @patron_attributes = grep { $_->type->opac_editable ? $_ : () } + Koha::Patron::Attributes->search( { borrowernumber => $self->borrowernumber } )->as_list; + + my $patron_attribute_types; + foreach my $attr (@patron_attributes) { + $patron_attribute_types->{ $attr->code } += 1; + } + + my $passed_attribute_types; + foreach my $attr ( @{$entered_attributes} ) { + $passed_attribute_types->{ $attr->{code} } += 1; + } + + my @changed_attributes; + + # Loop through the current patron attributes + foreach my $attribute_type ( keys %{$patron_attribute_types} ) { + if ( ( $patron_attribute_types->{$attribute_type} // q{} ) ne + ( $passed_attribute_types->{$attribute_type} // q{} ) ) + { + # count differs, overwrite all attributes for given type + foreach my $attr ( @{$entered_attributes} ) { + push @changed_attributes, $attr + if $attr->{code} eq $attribute_type; + } + } else { + + # count matches, check values + my $changes = 0; + foreach my $attr ( grep { $_->code eq $attribute_type } @patron_attributes ) { + $changes = 1 + unless any { $_->{attribute} eq $attr->attribute } @{$entered_attributes}; + last if $changes; + } + + if ($changes) { + foreach my $attr ( @{$entered_attributes} ) { + push @changed_attributes, $attr + if $attr->{code} eq $attribute_type; + } + } + } + } + + # Loop through passed attributes, looking for new ones + foreach my $attribute_type ( keys %{$passed_attribute_types} ) { + if ( !defined $patron_attribute_types->{$attribute_type} ) { + + # YAY, new stuff + foreach my $attr ( grep { $_->{code} eq $attribute_type } @{$entered_attributes} ) { + push @changed_attributes, $attr; + } + } + } + + return \@changed_attributes; +} + =head2 Internal methods =head3 _type diff --git a/Koha/REST/V1/Patrons/SelfRenewal.pm b/Koha/REST/V1/Patrons/SelfRenewal.pm index b28a0edaf9..5e490132cf 100644 --- a/Koha/REST/V1/Patrons/SelfRenewal.pm +++ b/Koha/REST/V1/Patrons/SelfRenewal.pm @@ -99,9 +99,12 @@ sub submit { $changes_detected++; } } - if ($changes_detected) { + my $updated_extended_attributes = + $patron->identify_updated_extended_attributes($extended_attributes); + if ( $changes_detected || scalar(@$updated_extended_attributes) ) { $changed_fields->{changed_fields} = join ',', keys %$changed_fields; - $changed_fields->{extended_attributes} = to_json($extended_attributes) if $extended_attributes; + $changed_fields->{extended_attributes} = to_json($updated_extended_attributes) + if scalar(@$updated_extended_attributes); $patron->request_modification($changed_fields); } } diff --git a/admin/categories.pl b/admin/categories.pl index ec2b66e484..205adaf539 100755 --- a/admin/categories.pl +++ b/admin/categories.pl @@ -50,7 +50,9 @@ if ( $op eq 'add_form' ) { my $category = Koha::Patron::Categories->find($categorycode); $template->param( category => scalar $category, - self_renewal_information_messages => parse_renewal_info_message( $category->self_renewal_information_message ) + self_renewal_information_messages => scalar $category + ? parse_renewal_info_message( $category->self_renewal_information_message ) + : [] ); if ( C4::Context->preference('EnhancedMessagingPreferences') ) { diff --git a/opac/opac-memberentry.pl b/opac/opac-memberentry.pl index 183fbb818e..fc194f6fc2 100755 --- a/opac/opac-memberentry.pl +++ b/opac/opac-memberentry.pl @@ -333,13 +333,14 @@ if ( $op eq 'cud-create' ) { $template->param( op => 'edit' ); } else { + my $patron = Koha::Patrons->find($borrowernumber); # If preferred name is not included but firstname is then set preferred_name to firstname $borrower{preferred_name} = $borrower{firstname} if defined $borrower{firstname} && !defined $borrower{preferred_name}; my %borrower_changes = DelUnchangedFields( $borrowernumber, %borrower ); $borrower_changes{'changed_fields'} = join ',', keys %borrower_changes; - my $extended_attributes_changes = FilterUnchangedAttributes( $borrowernumber, $attributes ); + my $extended_attributes_changes = $patron->identify_updated_extended_attributes($attributes); if ( $borrower_changes{'changed_fields'} || scalar @{$extended_attributes_changes} > 0 ) { ( $template, $borrowernumber, $cookie ) = get_template_and_user( @@ -354,7 +355,6 @@ if ( $op eq 'cud-create' ) { $borrower_changes{borrowernumber} = $borrowernumber; $borrower_changes{extended_attributes} = to_json($extended_attributes_changes); - my $patron = Koha::Patrons->find($borrowernumber); $patron->request_modification( \%borrower_changes ); $template->param( borrower => $patron->unblessed ); } else { @@ -633,67 +633,6 @@ sub DelEmptyFields { return %borrower; } -sub FilterUnchangedAttributes { - my ( $borrowernumber, $entered_attributes ) = @_; - - my @patron_attributes = grep { $_->type->opac_editable ? $_ : () } - Koha::Patron::Attributes->search( { borrowernumber => $borrowernumber } )->as_list; - - my $patron_attribute_types; - foreach my $attr (@patron_attributes) { - $patron_attribute_types->{ $attr->code } += 1; - } - - my $passed_attribute_types; - foreach my $attr ( @{$entered_attributes} ) { - $passed_attribute_types->{ $attr->{code} } += 1; - } - - my @changed_attributes; - - # Loop through the current patron attributes - foreach my $attribute_type ( keys %{$patron_attribute_types} ) { - if ( ( $patron_attribute_types->{$attribute_type} // q{} ) ne - ( $passed_attribute_types->{$attribute_type} // q{} ) ) - { - # count differs, overwrite all attributes for given type - foreach my $attr ( @{$entered_attributes} ) { - push @changed_attributes, $attr - if $attr->{code} eq $attribute_type; - } - } else { - - # count matches, check values - my $changes = 0; - foreach my $attr ( grep { $_->code eq $attribute_type } @patron_attributes ) { - $changes = 1 - unless any { $_->{value} eq $attr->attribute } @{$entered_attributes}; - last if $changes; - } - - if ($changes) { - foreach my $attr ( @{$entered_attributes} ) { - push @changed_attributes, $attr - if $attr->{code} eq $attribute_type; - } - } - } - } - - # Loop through passed attributes, looking for new ones - foreach my $attribute_type ( keys %{$passed_attribute_types} ) { - if ( !defined $patron_attribute_types->{$attribute_type} ) { - - # YAY, new stuff - foreach my $attr ( grep { $_->{code} eq $attribute_type } @{$entered_attributes} ) { - push @changed_attributes, $attr; - } - } - } - - return \@changed_attributes; -} - sub GeneratePatronAttributesForm { my ( $borrowernumber, $entered_attributes ) = @_; diff --git a/t/db_dependent/Koha/Patron.t b/t/db_dependent/Koha/Patron.t index 0649682d62..3f43629f8c 100755 --- a/t/db_dependent/Koha/Patron.t +++ b/t/db_dependent/Koha/Patron.t @@ -3941,3 +3941,128 @@ subtest "create_expiry_notice_parameters" => sub { is_deeply( $letter_params, $expected_return, 'Letter params generated correctly' ); $schema->storage->txn_rollback; }; + +subtest "identify_updated_extended_attributes" => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + } + ); + + my $unique_attribute_type = $builder->build_object( + { + class => 'Koha::Patron::Attribute::Types', + value => { + unique_id => 1, + repeatable => 0, + is_date => 0, + opac_editable => 1 + } + } + ); + my $repeatable_attribute_type = $builder->build_object( + { + class => 'Koha::Patron::Attribute::Types', + value => { + unique_id => 0, + repeatable => 1, + is_date => 0, + opac_editable => 1 + } + } + ); + my $normal_attribute_type = $builder->build_object( + { + class => 'Koha::Patron::Attribute::Types', + value => { + unique_id => 0, + repeatable => 0, + is_date => 0, + opac_editable => 1 + } + } + ); + + my $attributes = [ + { + attribute => 'my unique attribute 1', + code => $unique_attribute_type->code(), + }, + { + attribute => 'my repeatable attribute 1', + code => $repeatable_attribute_type->code(), + }, + { + attribute => 'my normal attribute 1', + code => $normal_attribute_type->code(), + } + ]; + $patron->extended_attributes($attributes); + + my $changed_attributes = [ + { + attribute => 'this is new', + code => $unique_attribute_type->code(), + }, + { + attribute => 'my repeatable attribute 1', + code => $repeatable_attribute_type->code(), + }, + { + attribute => 'my normal attribute 1', + code => $normal_attribute_type->code(), + } + ]; + + my $updated_attributes = $patron->identify_updated_extended_attributes($changed_attributes); + is( scalar(@$updated_attributes), 1, "Only the first one was changed" ); + + $attributes = [ + { + attribute => 'my unique attribute 1', + code => $unique_attribute_type->code(), + }, + { + attribute => 'my repeatable attribute 1', + code => $repeatable_attribute_type->code(), + }, + { + attribute => 'my repeatable attribute 2', + code => $repeatable_attribute_type->code(), + }, + { + attribute => 'my normal attribute 1', + code => $normal_attribute_type->code(), + } + ]; + + $patron->extended_attributes($attributes); + + $changed_attributes = [ + { + attribute => 'this is new', + code => $unique_attribute_type->code(), + }, + { + attribute => 'this repeatable one is also new', + code => $repeatable_attribute_type->code(), + }, + { + attribute => 'my repeatable attribute 2', + code => $repeatable_attribute_type->code(), + }, + { + attribute => 'my normal attribute 1', + code => $normal_attribute_type->code(), + } + ]; + + $updated_attributes = $patron->identify_updated_extended_attributes($changed_attributes); + is( scalar(@$updated_attributes), 3, "Two have now been updated, one of which is repeatable and has two values" ); + + $schema->storage->txn_rollback; +};