+
+sub FilterUnchangedAttributes {
+ my ( $borrowernumber, $entered_attributes ) = @_;
+
+ my @patron_attributes = grep {$_->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 } != $passed_attribute_types->{ $attribute_type } ) {
+ # 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 ) = @_;
+
+ # Get all attribute types and the values for this patron (if applicable)
+ my @types = grep { $_->opac_editable() or $_->opac_display }
+ Koha::Patron::Attribute::Types->search()->as_list();
+ if ( scalar(@types) == 0 ) {
+ return [];
+ }
+
+ my @displayable_attributes = grep { $_->opac_display }
+ Koha::Patron::Attributes->search({ borrowernumber => $borrowernumber })->as_list;
+
+ my %attr_values = ();
+
+ # Build the attribute values list either from the passed values
+ # or taken from the patron itself
+ if ( defined $entered_attributes ) {
+ foreach my $attr (@$entered_attributes) {
+ push @{ $attr_values{ $attr->{code} } }, $attr->{value};
+ }
+ }
+ elsif ( defined $borrowernumber ) {
+ my @editable_attributes = grep { $_->opac_editable } @displayable_attributes;
+ foreach my $attr (@editable_attributes) {
+ push @{ $attr_values{ $attr->code } }, $attr->attribute;
+ }
+ }
+
+ # Add the non-editable attributes (that don't come from the form)
+ foreach my $attr ( grep { !$_->opac_editable } @displayable_attributes ) {
+ push @{ $attr_values{ $attr->code } }, $attr->attribute;
+ }
+
+ # Find all existing classes
+ my @classes = sort( uniq( map { $_->class } @types ) );
+ my %items_by_class;
+
+ foreach my $attr_type (@types) {
+ push @{ $items_by_class{ $attr_type->class() } }, {
+ type => $attr_type,
+ # If editable, make sure there's at least one empty entry,
+ # to make the template's job easier
+ values => $attr_values{ $attr_type->code() } || ['']
+ }
+ unless !defined $attr_values{ $attr_type->code() }
+ and !$attr_type->opac_editable;
+ }
+
+ # Finally, build a list of containing classes
+ my @class_loop;
+ foreach my $class (@classes) {
+ next unless ( $items_by_class{$class} );
+
+ my $av = Koha::AuthorisedValues->search(
+ { category => 'PA_CLASS', authorised_value => $class } );
+
+ my $lib = $av->count ? $av->next->opac_description : $class;
+
+ push @class_loop,
+ {
+ class => $class,
+ items => $items_by_class{$class},
+ lib => $lib,
+ };
+ }
+
+ return \@class_loop;
+}
+
+sub ParsePatronAttributes {
+ my ( $borrowernumber, $cgi ) = @_;
+
+ my @codes = $cgi->multi_param('patron_attribute_code');
+ my @values = $cgi->multi_param('patron_attribute_value');
+
+ my @editable_attribute_types
+ = map { $_->code } Koha::Patron::Attribute::Types->search({ opac_editable => 1 });
+
+ my $ea = each_array( @codes, @values );
+ my @attributes;
+
+ my $delete_candidates = {};
+
+ while ( my ( $code, $value ) = $ea->() ) {
+ if ( any { $_ eq $code } @editable_attribute_types ) {
+ # It is an editable attribute
+ if ( !defined($value) or $value eq '' ) {
+ $delete_candidates->{$code} = 1
+ unless $delete_candidates->{$code};
+ }
+ else {
+ # we've got a value
+ push @attributes, { code => $code, value => $value };
+
+ # 'code' is no longer a delete candidate
+ delete $delete_candidates->{$code}
+ if defined $delete_candidates->{$code};
+ }
+ }
+ }
+
+ foreach my $code ( keys %{$delete_candidates} ) {
+ if ( Koha::Patron::Attributes->search({
+ borrowernumber => $borrowernumber, code => $code })->count > 0 )
+ {
+ push @attributes, { code => $code, value => '' }
+ unless any { $_->{code} eq $code } @attributes;
+ }
+ }
+
+ return \@attributes;
+}
+
+
+1;