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

(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt (-6 / +5 lines)
Lines 894-900 Link Here
894
                    [% FOREACH pa_class IN patron_attribute_classes %]
894
                    [% FOREACH pa_class IN patron_attribute_classes %]
895
                        [% IF pa_class.class %]
895
                        [% IF pa_class.class %]
896
                            <fieldset id="aai_[% pa_loo.class %]" class="rows patron-attributes">
896
                            <fieldset id="aai_[% pa_loo.class %]" class="rows patron-attributes">
897
                            <legend>[% pa_loo.lib %]</legend>
897
                            <legend>[% pa_class.lib %]</legend>
898
                        [% ELSE %]
898
                        [% ELSE %]
899
                            <fieldset class="rows patron-attributes">
899
                            <fieldset class="rows patron-attributes">
900
                            <legend>Additional information</legend>
900
                            <legend>Additional information</legend>
Lines 912-920 Link Here
912
                                                <select id="[% form_id %]" name="patron_attribute_value">
912
                                                <select id="[% form_id %]" name="patron_attribute_value">
913
                                                    <option value=""></option>
913
                                                    <option value=""></option>
914
                                                    [% FOREACH auth_val IN AuthorisedValues.Get( pa.type.authorised_value_category, 1 ) %]
914
                                                    [% FOREACH auth_val IN AuthorisedValues.Get( pa.type.authorised_value_category, 1 ) %]
915
                                                        [% IF ( auth_val.authorised_value == pa_value.value ) %]
915
                                                        [% IF ( auth_val.authorised_value == pa_value ) %]
916
                                                            <option value="[% auth_val.authorised_value %]" selected="selected">
916
                                                            <option value="[% auth_val.authorised_value %]" selected="selected">
917
                                                                [%# Yes, lib; GetAuthorisedValues takes care of intelligently setting this from lib_opac %]
918
                                                                [% auth_val.lib %]
917
                                                                [% auth_val.lib %]
919
                                                            </option>
918
                                                            </option>
920
                                                        [% ELSE %]
919
                                                        [% ELSE %]
Lines 925-931 Link Here
925
                                                    [% END %]
924
                                                    [% END %]
926
                                                </select>
925
                                                </select>
927
                                            [% ELSE %]
926
                                            [% ELSE %]
928
                                                <textarea rows="2" cols="30" id="[% form_id %]" name="patron_attribute_value">[% pa_value.value %]</textarea>
927
                                                <textarea rows="2" cols="30" id="[% form_id %]" name="patron_attribute_value">[% pa_value %]</textarea>
929
                                            [% END %]
928
                                            [% END %]
930
                                            <a href="#" class="clear-attribute">Clear</a>
929
                                            <a href="#" class="clear-attribute">Clear</a>
931
                                            [% IF ( pa.type.repeatable ) %]
930
                                            [% IF ( pa.type.repeatable ) %]
Lines 933-941 Link Here
933
                                            [% END %]
932
                                            [% END %]
934
                                        [% ELSE %]
933
                                        [% ELSE %]
935
                                            [% IF ( pa.type.authorised_value_category ) %]
934
                                            [% IF ( pa.type.authorised_value_category ) %]
936
                                                [% AuthorisedValues.GetByCode( pa.type.authorised_value_category, pa_value.value, 1 ) | html_line_break %]
935
                                                [% AuthorisedValues.GetByCode( pa.type.authorised_value_category, pa_value, 1 ) | html_line_break %]
937
                                            [% ELSE %]
936
                                            [% ELSE %]
938
                                                [% pa_value.value | html_line_break %]
937
                                                [% pa_value | html_line_break %]
939
                                            [% END %]
938
                                            [% END %]
940
                                        [% END %]
939
                                        [% END %]
941
                                    </li>
940
                                    </li>
(-)a/opac/opac-memberentry.pl (-60 / +112 lines)
Lines 29-42 use C4::Output; Link Here
29
use C4::Members;
29
use C4::Members;
30
use C4::Members::Attributes qw( GetBorrowerAttributes );
30
use C4::Members::Attributes qw( GetBorrowerAttributes );
31
use C4::Form::MessagingPreferences;
31
use C4::Form::MessagingPreferences;
32
use Koha::Patrons;
33
use Koha::Patron::Modification;
34
use Koha::Patron::Modifications;
35
use C4::Scrubber;
32
use C4::Scrubber;
36
use Email::Valid;
33
use Email::Valid;
37
use Koha::DateUtils;
34
use Koha::DateUtils;
38
use Koha::Libraries;
35
use Koha::Libraries;
36
use Koha::Patron::Attribute::Types;
37
use Koha::Patron::Attributes;
39
use Koha::Patron::Images;
38
use Koha::Patron::Images;
39
use Koha::Patron::Modification;
40
use Koha::Patron::Modifications;
41
use Koha::Patrons;
40
use Koha::Token;
42
use Koha::Token;
41
43
42
my $cgi = new CGI;
44
my $cgi = new CGI;
Lines 246-260 elsif ( $action eq 'update' ) { Link Here
246
                secret => md5_base64( Encode::encode( 'UTF-8', C4::Context->config('pass') ) ),
248
                secret => md5_base64( Encode::encode( 'UTF-8', C4::Context->config('pass') ) ),
247
            }),
249
            }),
248
        );
250
        );
249
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );
251
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( $borrowernumber, $attributes ) );
250
252
251
        $template->param( action => 'edit' );
253
        $template->param( action => 'edit' );
252
    }
254
    }
253
    else {
255
    else {
254
        my %borrower_changes = DelUnchangedFields( $borrowernumber, %borrower );
256
        my %borrower_changes = DelUnchangedFields( $borrowernumber, %borrower );
255
        my $extended_attributes_changes = ExtendedAttributesMatch( $borrowernumber, $attributes );
257
        my $extended_attributes_changes = FilterUnchagedAttributes( $borrowernumber, $attributes );
256
258
257
        if ( %borrower_changes || $extended_attributes_changes ) {
259
        if ( %borrower_changes || scalar @{$extended_attributes_changes} > 0 ) {
258
            ( $template, $borrowernumber, $cookie ) = get_template_and_user(
260
            ( $template, $borrowernumber, $cookie ) = get_template_and_user(
259
                {
261
                {
260
                    template_name   => "opac-memberentry-update-submitted.tt",
262
                    template_name   => "opac-memberentry-update-submitted.tt",
Lines 265-271 elsif ( $action eq 'update' ) { Link Here
265
            );
267
            );
266
268
267
            $borrower_changes{borrowernumber} = $borrowernumber;
269
            $borrower_changes{borrowernumber} = $borrowernumber;
268
            $borrower_changes{extended_attributes} = to_json($attributes);
270
            $borrower_changes{extended_attributes} = to_json($extended_attributes_changes);
269
271
270
            # FIXME update the following with
272
            # FIXME update the following with
271
            # Koha::Patron::Modifications->search({ borrowernumber => $borrowernumber })->delete;
273
            # Koha::Patron::Modifications->search({ borrowernumber => $borrowernumber })->delete;
Lines 286-292 elsif ( $action eq 'update' ) { Link Here
286
                action => 'edit',
288
                action => 'edit',
287
                nochanges => 1,
289
                nochanges => 1,
288
                borrower => GetMember( borrowernumber => $borrowernumber ),
290
                borrower => GetMember( borrowernumber => $borrowernumber ),
289
                patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ),
291
                patron_attribute_classes => GeneratePatronAttributesForm( $borrowernumber, $attributes ),
290
                csrf_token => Koha::Token->new->generate_csrf({
292
                csrf_token => Koha::Token->new->generate_csrf({
291
                    id     => Encode::encode( 'UTF-8', $borrower->{userid} ),
293
                    id     => Encode::encode( 'UTF-8', $borrower->{userid} ),
292
                    secret => md5_base64( Encode::encode( 'UTF-8', C4::Context->config('pass') ) ),
294
                    secret => md5_base64( Encode::encode( 'UTF-8', C4::Context->config('pass') ) ),
Lines 472-543 sub DelEmptyFields { Link Here
472
    return %borrower;
474
    return %borrower;
473
}
475
}
474
476
475
sub ExtendedAttributesMatch {
477
sub FilterUnchagedAttributes {
476
    my ( $borrowernumber, $entered_attributes ) = @_;
478
    my ( $borrowernumber, $entered_attributes ) = @_;
477
479
478
    my @patron_attributes_arr = GetBorrowerAttributes( $borrowernumber, 1 );
480
    my @patron_attributes = grep {$_->opac_editable} Koha::Patron::Attributes->search({ borrowernumber => $borrowernumber })->as_list;
479
    my $patron_attributes = $patron_attributes_arr[0];
481
482
    my $patron_attribute_types;
483
    foreach my $attr (@patron_attributes) {
484
        $patron_attribute_types->{ $attr->code } += 1;
485
    }
486
487
    my $passed_attribute_types;
488
    foreach my $attr (@{ $entered_attributes }) {
489
        $passed_attribute_types->{ $attr->{ code } } += 1;
490
    }
491
492
    my @changed_attributes;
493
494
    # Loop through the current patron attributes
495
    foreach my $attribute_type ( keys %{ $patron_attribute_types } ) {
496
        if ( $patron_attribute_types->{ $attribute_type } !=  $passed_attribute_types->{ $attribute_type } ) {
497
            # count differs, overwrite all attributes for given type
498
            foreach my $attr (@{ $entered_attributes }) {
499
                push @changed_attributes, $attr
500
                    if $attr->{ code } eq $attribute_type;
501
            }
502
        } else {
503
            # count matches, check values
504
            my $changes = 0;
505
            foreach my $attr (grep { $_->code eq $attribute_type } @patron_attributes) {
506
                $changes = 1
507
                    unless any { $_->{ value } eq $attr->attribute } @{ $entered_attributes };
508
                last if $changes;
509
            }
480
510
481
    if ( scalar @{$entered_attributes} != scalar @{$patron_attributes} ) {
511
            if ( $changes ) {
482
        return 1;
512
                foreach my $attr (@{ $entered_attributes }) {
513
                    push @changed_attributes, $attr
514
                        if $attr->{ code } eq $attribute_type;
515
                }
516
            }
517
        }
483
    }
518
    }
484
519
485
    foreach my $attr ( @{$patron_attributes} ) {
520
    # Loop through passed attributes, looking for new ones
486
        next if any {
521
    foreach my $attribute_type ( keys %{ $passed_attribute_types } ) {
487
            $_->{code} eq $attr->{code} and $_->{value} eq $attr->{value};
522
        if ( !defined $patron_attribute_types->{ $attribute_type } ) {
523
            # YAY, new stuff
524
            foreach my $attr (grep { $_->{code} eq $attribute_type } @{ $entered_attributes }) {
525
                push @changed_attributes, $attr;
526
            }
488
        }
527
        }
489
        @{$entered_attributes};
490
        return 1;
491
    }
528
    }
492
529
493
    return 0;
530
    return \@changed_attributes;
494
}
531
}
495
532
496
497
sub GeneratePatronAttributesForm {
533
sub GeneratePatronAttributesForm {
498
    my ( $borrowernumber, $entered_attributes ) = @_;
534
    my ( $borrowernumber, $entered_attributes ) = @_;
499
535
500
    # Get all attribute types and the values for this patron (if applicable)
536
    # Get all attribute types and the values for this patron (if applicable)
501
    my @types = C4::Members::AttributeTypes::GetAttributeTypes();
537
    my @types = grep { $_->opac_editable() or $_->opac_display }
502
538
        Koha::Patron::Attribute::Types->search()->as_list();
503
    if (scalar(@types) == 0) {
539
    if ( scalar(@types) == 0 ) {
504
        return [];
540
        return [];
505
    }
541
    }
506
542
507
    my %attr_values = ();
543
    my @displayable_attributes = grep { $_->opac_display }
544
        Koha::Patron::Attributes->search({ borrowernumber => $borrowernumber })->as_list;
508
545
509
    if ( $borrowernumber ) {
546
    my %attr_values = ();
510
        my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
511
547
512
        # Remap the patron's attributes into a hash of arrayrefs per attribute (depends on
548
    # Build the attribute values list either from the passed values
513
        # autovivification)
549
    # or taken from the patron itself
514
        foreach my $attr (@$attributes) {
550
    if ( defined $entered_attributes ) {
515
            push @{ $attr_values{ $attr->{code} } }, $attr;
551
        foreach my $attr (@$entered_attributes) {
552
            push @{ $attr_values{ $attr->{code} } }, $attr->{value};
516
        }
553
        }
517
    }
554
    }
518
555
    elsif ( defined $borrowernumber ) {
519
    if ( $entered_attributes ) {
556
        my @editable_attributes = grep { $_->opac_editable } @displayable_attributes;
520
        foreach my $attr (@$entered_attributes) {
557
        foreach my $attr (@editable_attributes) {
521
            push @{ $attr_values{ $attr->{code} } }, $attr;
558
            push @{ $attr_values{ $attr->code } }, $attr->attribute;
522
        }
559
        }
523
    }
560
    }
524
561
562
    # Add the non-editable attributes (that don't come from the form)
563
    foreach my $attr ( grep { !$_->opac_editable } @displayable_attributes ) {
564
        push @{ $attr_values{ $attr->code } }, $attr->attribute;
565
    }
566
525
    # Find all existing classes
567
    # Find all existing classes
526
    my @classes = uniq( map { $_->{class} } @types );
568
    my @classes = sort( uniq( map { $_->class } @types ) );
527
    @classes = sort @classes;
528
    my %items_by_class;
569
    my %items_by_class;
529
570
530
    foreach my $attr_type_desc (@types) {
571
    foreach my $attr_type (@types) {
531
        my $attr_type = C4::Members::AttributeTypes->fetch( $attr_type_desc->{code} );
532
        # Make sure this attribute should be displayed in the OPAC
533
        next unless ( $attr_type->opac_display() );
534
        # Then, make sure it either has values or is editable
535
        next unless ( $attr_values{ $attr_type->code() } || $attr_type->opac_editable() );
536
537
        push @{ $items_by_class{ $attr_type->class() } }, {
572
        push @{ $items_by_class{ $attr_type->class() } }, {
538
            type => $attr_type,
573
            type => $attr_type,
539
            # If editable, make sure there's at least one empty entry, to make the template's job easier
574
            # If editable, make sure there's at least one empty entry,
540
            values => $attr_values{ $attr_type->code() } || [{}]
575
            # to make the template's job easier
576
            values => $attr_values{ $attr_type->code() } || ['']
541
        };
577
        };
542
    }
578
    }
543
579
Lines 546-588 sub GeneratePatronAttributesForm { Link Here
546
    foreach my $class (@classes) {
582
    foreach my $class (@classes) {
547
        next unless ( $items_by_class{$class} );
583
        next unless ( $items_by_class{$class} );
548
584
549
        my $av = Koha::AuthorisedValues->search({ category => 'PA_CLASS', authorised_value => $class });
585
        my $av = Koha::AuthorisedValues->search(
586
            { category => 'PA_CLASS', authorised_value => $class } );
587
550
        my $lib = $av->count ? $av->next->opac_description : $class;
588
        my $lib = $av->count ? $av->next->opac_description : $class;
551
589
552
        push @class_loop, {
590
        push @class_loop,
591
            {
553
            class => $class,
592
            class => $class,
554
            items => $items_by_class{$class},
593
            items => $items_by_class{$class},
555
            lib   => $lib,
594
            lib   => $lib,
556
        };
595
            };
557
    }
596
    }
558
597
559
    return \@class_loop;
598
    return \@class_loop;
560
}
599
}
561
600
562
sub ParsePatronAttributes {
601
sub ParsePatronAttributes {
563
    my ($borrowernumber,$cgi) = @_;
602
    my ( $borrowernumber, $cgi ) = @_;
564
603
565
    my @codes  = $cgi->multi_param('patron_attribute_code');
604
    my @codes  = $cgi->multi_param('patron_attribute_code');
566
    my @values = $cgi->multi_param('patron_attribute_value');
605
    my @values = $cgi->multi_param('patron_attribute_value');
567
606
568
    my $ea = each_array( @codes, @values );
607
    my $ea = each_array( @codes, @values );
569
    my @attributes;
608
    my @attributes;
570
    my %dups = ();
609
610
    my $delete_candidates = {};
571
611
572
    while ( my ( $code, $value ) = $ea->() ) {
612
    while ( my ( $code, $value ) = $ea->() ) {
573
        # Don't skip if the patron already has attributes with $code, because
613
        if ( !defined($value) or $value eq '' ) {
574
        # it means we are being requested to remove the attributes.
614
            $delete_candidates->{$code} = 1
575
        next
615
                unless $delete_candidates->{$code};
576
            unless defined($value) and $value ne ''
616
        }
577
            or Koha::Patron::Attributes->search(
617
        else {
578
            { borrowernumber => $borrowernumber, code => $code } )->count > 0;
618
            # we've got a value
579
        next if exists $dups{$code}->{$value};
619
            push @attributes, { code => $code, value => $value };
580
        $dups{$code}->{$value} = 1;
620
621
            # 'code' is no longer a delete candidate
622
            delete $delete_candidates->{$code};
623
        }
624
    }
581
625
582
        push @attributes, { code => $code, value => $value };
626
    foreach my $code ( keys %{$delete_candidates} ) {
627
        if (Koha::Patron::Attributes->search(
628
                { borrowernumber => $borrowernumber, code => $code }
629
            )->count > 0
630
            )
631
        {
632
            push @attributes, { code => $code, value => '' }
633
                unless any { $_->{code} eq $code } @attributes;
634
        }
583
    }
635
    }
584
636
585
    return \@attributes;
637
    return \@attributes;
586
}
638
}
587
639
640
588
1;
641
1;
589
- 

Return to bug 13757