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

(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/patron-attr-types.tt (-1 / +1 lines)
Lines 322-328 function CheckAttributeTypeForm(f) { Link Here
322
            <td>[% item.code |html %]</td>
322
            <td>[% item.code |html %]</td>
323
            <td>[% item.description %]</td>
323
            <td>[% item.description %]</td>
324
            <td>
324
            <td>
325
                [% IF item.branches.size > 0 %]
325
                [% IF ( item.branches ) %]
326
                    [% branches_str = "" %]
326
                    [% branches_str = "" %]
327
                    [% FOREACH branch IN item.branches %]
327
                    [% FOREACH branch IN item.branches %]
328
                        [% branches_str = branches_str _ " " _ branch.branchname _ "(" _ branch.branchcode _ ")" %]
328
                        [% branches_str = branches_str _ " " _ branch.branchname _ "(" _ branch.branchcode _ ")" %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt (-19 / +90 lines)
Lines 1-6 Link Here
1
[% USE AuthorisedValues %]
1
[% USE Categories %]
2
[% USE Categories %]
2
[% USE Koha %]
3
[% USE Koha %]
3
[% USE KohaDates %]
4
[% USE KohaDates %]
5
[% USE Math %]
4
[% SET userupdateview = 1 %]
6
[% SET userupdateview = 1 %]
5
7
6
[% INCLUDE 'doc-head-open.inc' %]
8
[% INCLUDE 'doc-head-open.inc' %]
Lines 110-115 Link Here
110
                        </ol>
112
                        </ol>
111
                    </fieldset>
113
                    </fieldset>
112
                [% END %]
114
                [% END %]
115
                [% IF ( extended_unique_id_failed_code ) %]
116
                    <div class="alert" id="extended_unique_id_failed"><a href="#patron-attr-start-[% extended_unique_id_failed_code %]">[% extended_unique_id_failed_description %]</a> value <i>[% extended_unique_id_failed_value %]</i> is already in use.</div>
117
                [% END %]
113
118
114
                <form method="post" action="/cgi-bin/koha/opac-memberentry.pl" id="memberentry-form">
119
                <form method="post" action="/cgi-bin/koha/opac-memberentry.pl" id="memberentry-form">
115
120
Lines 861-867 Link Here
861
                    </fieldset>
866
                    </fieldset>
862
               [% END %]
867
               [% END %]
863
868
864
               [% UNLESS action == 'edit' %]
869
                [% IF ( Koha.Preference('ExtendedPatronAttributes') && patron_attribute_classes.size ) %]
870
                    [% FOREACH pa_class IN patron_attribute_classes %]
871
                        [% IF pa_class.class %]
872
                            <fieldset id="aai_[% pa_loo.class %]" class="rows patron-attributes">
873
                            <legend>[% pa_loo.lib %]</legend>
874
                        [% ELSE %]
875
                            <fieldset class="rows patron-attributes">
876
                            <legend>Additional information</legend>
877
                        [% END %]
878
                        <ol class="attributes_table">
879
                            [% FOREACH pa IN pa_class.items %]
880
                                [% FOREACH pa_value IN pa.values %]
881
                                    [% IF loop.first %]<a name="patron-attr-start-[% pa.type.code %]"></a>[% END %]
882
                                    [% form_id = 'patron-attr-' _ Math.int( Math.rand(1000000) ) %]
883
                                    <li data-category_code="[% pa.type.category_code %]">
884
                                        <label for="[% form_id %]">[% pa.type.description %]: </label>
885
                                        [% IF pa.type.opac_editable %]
886
                                            <input type="hidden" name="patron_attribute_code" value="[% pa.type.code |html %]" />
887
                                            [% IF ( pa.type.authorised_value_category ) %]
888
                                                <select id="[% form_id %]" name="patron_attribute_value">
889
                                                    <option value=""></option>
890
                                                    [% FOREACH auth_val IN AuthorisedValues.Get( pa.type.authorised_value_category, pa_value.value || '', 1 ) %]
891
                                                        [% IF ( auth_val.selected ) %]
892
                                                            <option value="[% auth_val.authorised_value %]" selected="selected">
893
                                                                [%# Yes, lib; GetAuthorisedValues takes care of intelligently setting this from lib_opac %]
894
                                                                [% auth_val.lib %]
895
                                                            </option>
896
                                                        [% ELSE %]
897
                                                            <option value="[% auth_val.authorised_value %]" >
898
                                                                [% auth_val.lib %]
899
                                                            </option>
900
                                                        [% END %]
901
                                                    [% END %]
902
                                                </select>
903
                                            [% ELSE %]
904
                                                <textarea rows="2" cols="30" id="[% form_id %]" name="patron_attribute_value">[% pa_value.value %]</textarea>
905
                                            [% END %]
906
                                            [% IF ( pa.type.password_allowed ) %]
907
                                                (<label class="lradio" for="[% form_id %]_password">Password:</label>
908
                                                <input type="password" maxlength="64" value="[% pa_value.password %]" id="[% form_id %]_password" name="patron_attribute_password" />)
909
                                            [% ELSE %]
910
                                                [%# To keep the form inputs lined up in the POST %]
911
                                                <input type="hidden" name="patron_attribute_password" value="" />
912
                                            [% END %]
913
                                            <a href="#" class="clear-attribute">Clear</a>
914
                                            [% IF ( pa.type.repeatable ) %]
915
                                            <a href="#" class="clone-attribute">New</a>
916
                                            [% END %]
917
                                        [% ELSE %]
918
                                            [% IF ( pa.type.authorised_value_category ) %]
919
                                                [% AuthorisedValues.GetByCode( pa.type.authorised_value, pa_value.value, 1 ) %]
920
                                            [% ELSE %]
921
                                                [% pa_value.value | html_line_break %]
922
                                            [% END %]
923
                                            [% IF ( pa_value.password ) %]
924
                                                (Password: *******)
925
                                            [% END %]
926
                                        [% END %]
927
                                    </li>
928
                                [% END %]
929
                            [% END %]
930
                        </ol>
931
                        </fieldset>
932
                    [% END %]
933
                [% END %]
934
935
                [% UNLESS action == 'edit' %]
865
                    <fieldset class="rows" id="memberentry_captcha">
936
                    <fieldset class="rows" id="memberentry_captcha">
866
                        <ol>
937
                        <ol>
867
938
Lines 878-901 Link Here
878
                    </fieldset>
949
                    </fieldset>
879
                [% END %]
950
                [% END %]
880
951
881
                [% IF ( borrower.ExtendedPatronAttributes ) %]
882
                    <fieldset class="rows">
883
                        <legend>Additional information</legend>
884
                        <ol>
885
                            [% FOREACH patron_attribute IN borrower.patron_attributes %]
886
                                <li>
887
                                    <label>[% patron_attribute.description %]:</label>
888
                                    [% IF ( patron_attribute.value_description ) %]
889
                                        [% patron_attribute.value_description %]
890
                                    [% ELSE %]
891
                                        [% patron_attribute.value |html_line_break %]
892
                                    [% END %]
893
                                </li>
894
                            [% END %]
895
                        </ol>
896
                    </fieldset>
897
                [% END %]
898
899
                [% IF action == 'edit' %]
952
                [% IF action == 'edit' %]
900
                    [% IF OPACPatronDetails %]
953
                    [% IF OPACPatronDetails %]
901
                        <fieldset class="action">
954
                        <fieldset class="action">
Lines 982-987 Link Here
982
                     });
1035
                     });
983
                });
1036
                });
984
            [% END %]
1037
            [% END %]
1038
1039
            $(".patron-attributes").on( 'click', '.clear-attribute', function() {
1040
                $(this).parent()
1041
                    .find('textarea').attr('value', '').end()
1042
                    .find('select').attr('value', '').end();
1043
1044
                return false;
1045
            } );
1046
1047
            $(".patron-attributes").on( 'click', '.clone-attribute', function() {
1048
                var clone = $(this).parent().clone().insertAfter( $(this).parent() );
1049
1050
                var newId = 50 + parseInt(Math.random() * 100000);
1051
                $('input[type!="hidden"],select,textarea', clone).attr('id', 'patron-attr-' + newId).attr('value', '');
1052
                $("label", clone).attr('for', 'patron-attr-' + newId).attr('value', '');
1053
1054
                return false;
1055
            } );
985
        });
1056
        });
986
    //]]>
1057
    //]]>
987
    </script>
1058
    </script>
(-)a/opac/opac-memberentry.pl (-11 / +115 lines)
Lines 19-27 use Modern::Perl; Link Here
19
19
20
use CGI qw ( -utf8 );
20
use CGI qw ( -utf8 );
21
use Digest::MD5 qw( md5_base64 md5_hex );
21
use Digest::MD5 qw( md5_base64 md5_hex );
22
use List::MoreUtils qw( each_array uniq );
22
use String::Random qw( random_string );
23
use String::Random qw( random_string );
23
24
24
use C4::Auth;
25
use C4::Auth;
26
use C4::Koha qw( GetAuthorisedValueByCode );
25
use C4::Output;
27
use C4::Output;
26
use C4::Members;
28
use C4::Members;
27
use C4::Form::MessagingPreferences;
29
use C4::Form::MessagingPreferences;
Lines 71-76 $template->param( Link Here
71
    OPACPatronDetails => C4::Context->preference('OPACPatronDetails'),
73
    OPACPatronDetails => C4::Context->preference('OPACPatronDetails'),
72
);
74
);
73
75
76
my $attributes = ParsePatronAttributes($cgi);
77
my $conflicting_attribute = 0;
78
79
foreach my $attr (@$attributes) {
80
    unless ( C4::Members::Attributes::CheckUniqueness($attr->{code}, $attr->{value}, $borrowernumber) ) {
81
        my $attr_info = C4::Members::AttributeTypes->fetch($attr->{code});
82
        $template->param(
83
            extended_unique_id_failed_code => $attr->{code},
84
            extended_unique_id_failed_value => $attr->{value},
85
            extended_unique_id_failed_description => $attr_info->description()
86
        );
87
        $conflicting_attribute = 1;
88
    }
89
}
90
74
if ( $action eq 'create' ) {
91
if ( $action eq 'create' ) {
75
92
76
    my %borrower = ParseCgiForBorrower($cgi);
93
    my %borrower = ParseCgiForBorrower($cgi);
Lines 87-93 if ( $action eq 'create' ) { Link Here
87
        $cardnumber_error_code = checkcardnumber( $borrower{cardnumber}, $borrower{borrowernumber} );
104
        $cardnumber_error_code = checkcardnumber( $borrower{cardnumber}, $borrower{borrowernumber} );
88
    }
105
    }
89
106
90
    if ( @empty_mandatory_fields || @$invalidformfields || $cardnumber_error_code ) {
107
    if ( @empty_mandatory_fields || @$invalidformfields || $cardnumber_error_code || $conflicting_attribute ) {
91
        if ( $cardnumber_error_code == 1 ) {
108
        if ( $cardnumber_error_code == 1 ) {
92
            $template->param( cardnumber_already_exists => 1 );
109
            $template->param( cardnumber_already_exists => 1 );
93
        } elsif ( $cardnumber_error_code == 2 ) {
110
        } elsif ( $cardnumber_error_code == 2 ) {
Lines 99-104 if ( $action eq 'create' ) { Link Here
99
            invalid_form_fields    => $invalidformfields,
116
            invalid_form_fields    => $invalidformfields,
100
            borrower               => \%borrower
117
            borrower               => \%borrower
101
        );
118
        );
119
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );
102
    }
120
    }
103
    elsif (
121
    elsif (
104
        md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') )
122
        md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') )
Lines 107-112 if ( $action eq 'create' ) { Link Here
107
            failed_captcha => 1,
125
            failed_captcha => 1,
108
            borrower       => \%borrower
126
            borrower       => \%borrower
109
        );
127
        );
128
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );
110
    }
129
    }
111
    else {
130
    else {
112
        if (
131
        if (
Lines 163-168 if ( $action eq 'create' ) { Link Here
163
                  C4::Context->preference('OpacPasswordChange') );
182
                  C4::Context->preference('OpacPasswordChange') );
164
183
165
            my ( $borrowernumber, $password ) = AddMember_Opac(%borrower);
184
            my ( $borrowernumber, $password ) = AddMember_Opac(%borrower);
185
            C4::Members::Attributes::SetBorrowerAttributes( $borrowernumber, $attributes );
166
            C4::Form::MessagingPreferences::handle_form_action($cgi, { borrowernumber => $borrowernumber }, $template, 1, C4::Context->preference('PatronSelfRegistrationDefaultCategory') ) if $borrowernumber && C4::Context->preference('EnhancedMessagingPreferences');
186
            C4::Form::MessagingPreferences::handle_form_action($cgi, { borrowernumber => $borrowernumber }, $template, 1, C4::Context->preference('PatronSelfRegistrationDefaultCategory') ) if $borrowernumber && C4::Context->preference('EnhancedMessagingPreferences');
167
187
168
            $template->param( password_cleartext => $password );
188
            $template->param( password_cleartext => $password );
Lines 185-196 elsif ( $action eq 'update' ) { Link Here
185
      CheckMandatoryFields( \%borrower_changes, $action );
205
      CheckMandatoryFields( \%borrower_changes, $action );
186
    my $invalidformfields = CheckForInvalidFields(\%borrower);
206
    my $invalidformfields = CheckForInvalidFields(\%borrower);
187
207
188
    if (@empty_mandatory_fields || @$invalidformfields) {
208
    if (@empty_mandatory_fields || @$invalidformfields || $conflicting_attribute) {
189
        $template->param(
209
        $template->param(
190
            empty_mandatory_fields => \@empty_mandatory_fields,
210
            empty_mandatory_fields => \@empty_mandatory_fields,
191
            invalid_form_fields    => $invalidformfields,
211
            invalid_form_fields    => $invalidformfields,
192
            borrower               => \%borrower
212
            borrower               => \%borrower
193
        );
213
        );
214
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );
194
215
195
        $template->param( action => 'edit' );
216
        $template->param( action => 'edit' );
196
    }
217
    }
Lines 228-241 elsif ( $action eq 'update' ) { Link Here
228
elsif ( $action eq 'edit' ) {    #Display logged in borrower's data
249
elsif ( $action eq 'edit' ) {    #Display logged in borrower's data
229
    my $borrower = GetMember( borrowernumber => $borrowernumber );
250
    my $borrower = GetMember( borrowernumber => $borrowernumber );
230
251
231
    if (C4::Context->preference('ExtendedPatronAttributes')) {
232
        my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, 'opac');
233
        if (scalar(@$attributes) > 0) {
234
            $borrower->{ExtendedPatronAttributes} = 1;
235
            $borrower->{patron_attributes} = $attributes;
236
        }
237
    }
238
239
    $template->param(
252
    $template->param(
240
        borrower  => $borrower,
253
        borrower  => $borrower,
241
        guarantor => scalar Koha::Borrowers->find($borrowernumber)->guarantor(),
254
        guarantor => scalar Koha::Borrowers->find($borrowernumber)->guarantor(),
Lines 251-256 elsif ( $action eq 'edit' ) { #Display logged in borrower's data Link Here
251
        }
264
        }
252
    }
265
    }
253
266
267
    $template->param( patron_attribute_classes => GeneratePatronAttributesForm( $borrower ) );
268
} else {
269
    $template->param( patron_attribute_classes => GeneratePatronAttributesForm() );
254
}
270
}
255
271
256
my $captcha = random_string("CCCCC");
272
my $captcha = random_string("CCCCC");
Lines 397-399 sub DelEmptyFields { Link Here
397
413
398
    return %borrower;
414
    return %borrower;
399
}
415
}
400
- 
416
417
sub GeneratePatronAttributesForm {
418
    my ( $borrower, $entered_attributes ) = @_;
419
420
    use Data::Dumper; warn Dumper( $entered_attributes );
421
422
    # Get all attribute types and the values for this patron (if applicable)
423
    my @types = C4::Members::AttributeTypes::GetAttributeTypes();
424
425
    if (scalar(@types) == 0) {
426
        return [];
427
    }
428
429
    my %attr_values = ();
430
431
    if ( $borrower ) {
432
        my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
433
434
        # Remap the patron's attributes into a hash of arrayrefs per attribute (depends on
435
        # autovivification)
436
        foreach my $attr (@$attributes) {
437
            push @{ $attr_values{ $attr->{code} } }, $attr;
438
        }
439
    }
440
441
    if ( $entered_attributes ) {
442
        foreach my $attr (@$entered_attributes) {
443
            push @{ $attr_values{ $attr->{code} } }, $attr;
444
        }
445
    }
446
447
    # Find all existing classes
448
    my @classes = uniq( map { $_->{class} } @types );
449
    @classes = sort @classes;
450
    my %items_by_class;
451
452
    foreach my $attr_type_desc (@types) {
453
        my $attr_type = C4::Members::AttributeTypes->fetch( $attr_type_desc->{code} );
454
        # Make sure this attribute should be displayed in the OPAC
455
        next unless ( $attr_type->opac_display() );
456
        # Then, make sure it either has values or is editable
457
        next unless ( $attr_values{ $attr_type->code() } || $attr_type->opac_editable() );
458
459
        push @{ $items_by_class{ $attr_type->class() } }, {
460
            type => $attr_type,
461
            # If editable, make sure there's at least one empty entry, to make the template's job easier
462
            values => $attr_values{ $attr_type->code() } || [{}]
463
        };
464
    }
465
466
    use Data::Dumper; warn Dumper( \%items_by_class );
467
468
    # Finally, build a list of containing classes
469
    my @class_loop;
470
    foreach my $class (@classes) {
471
        next unless ( $items_by_class{$class} );
472
473
        my $lib = GetAuthorisedValueByCode( 'PA_CLASS', $class, 1 ) || $class;
474
        push @class_loop, {
475
            class => $class,
476
            items => $items_by_class{$class},
477
            lib   => $lib,
478
        };
479
    }
480
481
    return \@class_loop;
482
}
483
484
sub ParsePatronAttributes {
485
    my ( $cgi ) = @_;
486
487
    my @codes = $cgi->param('patron_attribute_code');
488
    my @values = $cgi->param('patron_attribute_value');
489
    my @passwords = $cgi->param('patron_attribute_password');
490
491
    my $ea = each_array( @codes, @values, @passwords );
492
    my @attributes;
493
    my %dups = ();
494
495
    while ( my ( $code, $value, $password ) = $ea->() ) {
496
        next unless defined($value) and $value ne '';
497
        next if exists $dups{$code}->{$value};
498
        $dups{$code}->{$value} = 1;
499
500
        push @attributes, { code => $code, value => $value, password => $password };
501
    }
502
503
    return \@attributes;
504
}

Return to bug 13757