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

(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt (-18 / +90 lines)
Lines 1-5 Link Here
1
[% USE AuthorisedValues %]
1
[% USE Koha %]
2
[% USE Koha %]
2
[% USE KohaDates %]
3
[% USE KohaDates %]
4
[% USE Math %]
3
[% SET userupdateview = 1 %]
5
[% SET userupdateview = 1 %]
4
6
5
[% INCLUDE 'doc-head-open.inc' %]
7
[% INCLUDE 'doc-head-open.inc' %]
Lines 70-75 Link Here
70
                    <div class="alert">You typed in the wrong characters in the box before submitting. Please try again.</div>
72
                    <div class="alert">You typed in the wrong characters in the box before submitting. Please try again.</div>
71
                [% END %]
73
                [% END %]
72
74
75
                [% IF ( extended_unique_id_failed_code ) %]
76
                    <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>
77
                [% END %]
78
73
                <form method="post" action="/cgi-bin/koha/opac-memberentry.pl" id="memberentry-form">
79
                <form method="post" action="/cgi-bin/koha/opac-memberentry.pl" id="memberentry-form">
74
80
75
                [% UNLESS hidden.defined('branchcode') %]
81
                [% UNLESS hidden.defined('branchcode') %]
Lines 750-755 Link Here
750
                    </fieldset>
756
                    </fieldset>
751
                [% END %]
757
                [% END %]
752
758
759
                [% IF ( Koha.Preference('ExtendedPatronAttributes') && patron_attribute_classes.size ) %]
760
                    [% FOREACH pa_class IN patron_attribute_classes %]
761
                        [% IF pa_class.class %]
762
                            <fieldset id="aai_[% pa_loo.class %]" class="rows patron-attributes">
763
                            <legend>[% pa_loo.lib %]</legend>
764
                        [% ELSE %]
765
                            <fieldset class="rows patron-attributes">
766
                            <legend>Additional information</legend>
767
                        [% END %]
768
                        <ol class="attributes_table">
769
                            [% FOREACH pa IN pa_class.items %]
770
                                [% FOREACH pa_value IN pa.values %]
771
                                    [% IF loop.first %]<a name="patron-attr-start-[% pa.type.code %]"></a>[% END %]
772
                                    [% form_id = 'patron-attr-' _ Math.int( Math.rand(1000000) ) %]
773
                                    <li data-category_code="[% pa.type.category_code %]">
774
                                        <label for="[% form_id %]">[% pa.type.description %]: </label>
775
                                        [% IF pa.type.opac_editable %]
776
                                            <input type="hidden" name="patron_attribute_code" value="[% pa.type.code |html %]" />
777
                                            [% IF ( pa.type.authorised_value_category ) %]
778
                                                <select id="[% form_id %]" name="patron_attribute_value">
779
                                                    <option value=""></option>
780
                                                    [% FOREACH auth_val IN AuthorisedValues.Get( pa.type.authorised_value_category, pa_value.value || '', 1 ) %]
781
                                                        [% IF ( auth_val.selected ) %]
782
                                                            <option value="[% auth_val.authorised_value %]" selected="selected">
783
                                                                [%# Yes, lib; GetAuthorisedValues takes care of intelligently setting this from lib_opac %]
784
                                                                [% auth_val.lib %]
785
                                                            </option>
786
                                                        [% ELSE %]
787
                                                            <option value="[% auth_val.authorised_value %]" >
788
                                                                [% auth_val.lib %]
789
                                                            </option>
790
                                                        [% END %]
791
                                                    [% END %]
792
                                                </select>
793
                                            [% ELSE %]
794
                                                <textarea rows="2" cols="30" id="[% form_id %]" name="patron_attribute_value">[% pa_value.value %]</textarea>
795
                                            [% END %]
796
                                            [% IF ( pa.type.password_allowed ) %]
797
                                                (<label class="lradio" for="[% form_id %]_password">Password:</label>
798
                                                <input type="password" maxlength="64" value="[% pa_value.password %]" id="[% form_id %]_password" name="patron_attribute_password" />)
799
                                            [% ELSE %]
800
                                                [%# To keep the form inputs lined up in the POST %]
801
                                                <input type="hidden" name="patron_attribute_password" value="" />
802
                                            [% END %]
803
                                            <a href="#" class="clear-attribute">Clear</a>
804
                                            [% IF ( pa.type.repeatable ) %]
805
                                            <a href="#" class="clone-attribute">New</a>
806
                                            [% END %]
807
                                        [% ELSE %]
808
                                            [% IF ( pa.type.authorised_value_category ) %]
809
                                                [% AuthorisedValues.GetByCode( pa.type.authorised_value, pa_value.value, 1 ) %]
810
                                            [% ELSE %]
811
                                                [% pa_value.value | html_line_break %]
812
                                            [% END %]
813
                                            [% IF ( pa_value.password ) %]
814
                                                (Password: *******)
815
                                            [% END %]
816
                                        [% END %]
817
                                    </li>
818
                                [% END %]
819
                            [% END %]
820
                        </ol>
821
                        </fieldset>
822
                    [% END %]
823
                [% END %]
824
753
                [% UNLESS action == 'edit' %]
825
                [% UNLESS action == 'edit' %]
754
                    <fieldset class="rows" id="memberentry_captcha">
826
                    <fieldset class="rows" id="memberentry_captcha">
755
                        <ol>
827
                        <ol>
Lines 766-789 Link Here
766
                    </fieldset>
838
                    </fieldset>
767
                [% END %]
839
                [% END %]
768
840
769
                [% IF ( borrower.ExtendedPatronAttributes ) %]
770
                    <fieldset class="rows">
771
                        <legend>Additional information</legend>
772
                        <ol>
773
                            [% FOREACH patron_attribute IN borrower.patron_attributes %]
774
                                <li>
775
                                    <label>[% patron_attribute.description %]:</label>
776
                                    [% IF ( patron_attribute.value_description ) %]
777
                                        [% patron_attribute.value_description %]
778
                                    [% ELSE %]
779
                                        [% patron_attribute.value |html_line_break %]
780
                                    [% END %]
781
                                </li>
782
                            [% END %]
783
                        </ol>
784
                    </fieldset>
785
                [% END %]
786
787
                [% IF action == 'edit' %]
841
                [% IF action == 'edit' %]
788
                    [% IF OPACPatronDetails %]
842
                    [% IF OPACPatronDetails %]
789
                        <fieldset class="action">
843
                        <fieldset class="action">
Lines 853-858 Link Here
853
                    error.css('width', 'auto');
907
                    error.css('width', 'auto');
854
                }
908
                }
855
            });
909
            });
910
911
            $(".patron-attributes").on( 'click', '.clear-attribute', function() {
912
                $(this).parent()
913
                    .find('textarea').attr('value', '').end()
914
                    .find('select').attr('value', '').end();
915
916
                return false;
917
            } );
918
919
            $(".patron-attributes").on( 'click', '.clone-attribute', function() {
920
                var clone = $(this).parent().clone().insertAfter( $(this).parent() );
921
922
                var newId = 50 + parseInt(Math.random() * 100000);
923
                $('input[type!="hidden"],select,textarea', clone).attr('id', 'patron-attr-' + newId).attr('value', '');
924
                $("label", clone).attr('for', 'patron-attr-' + newId).attr('value', '');
925
926
                return false;
927
            } );
856
        });
928
        });
857
    //]]>
929
    //]]>
858
    </script>
930
    </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 70-75 $template->param( Link Here
70
    OPACPatronDetails => C4::Context->preference('OPACPatronDetails'),
72
    OPACPatronDetails => C4::Context->preference('OPACPatronDetails'),
71
);
73
);
72
74
75
my $attributes = ParsePatronAttributes($cgi);
76
my $conflicting_attribute = 0;
77
78
foreach my $attr (@$attributes) {
79
    unless ( C4::Members::Attributes::CheckUniqueness($attr->{code}, $attr->{value}, $borrowernumber) ) {
80
        my $attr_info = C4::Members::AttributeTypes->fetch($attr->{code});
81
        $template->param(
82
            extended_unique_id_failed_code => $attr->{code},
83
            extended_unique_id_failed_value => $attr->{value},
84
            extended_unique_id_failed_description => $attr_info->description()
85
        );
86
        $conflicting_attribute = 1;
87
    }
88
}
89
73
if ( $action eq 'create' ) {
90
if ( $action eq 'create' ) {
74
91
75
    my %borrower = ParseCgiForBorrower($cgi);
92
    my %borrower = ParseCgiForBorrower($cgi);
Lines 79-90 if ( $action eq 'create' ) { Link Here
79
    my @empty_mandatory_fields = CheckMandatoryFields( \%borrower, $action );
96
    my @empty_mandatory_fields = CheckMandatoryFields( \%borrower, $action );
80
    my $invalidformfields = CheckForInvalidFields(\%borrower);
97
    my $invalidformfields = CheckForInvalidFields(\%borrower);
81
98
82
    if (@empty_mandatory_fields || @$invalidformfields) {
99
    if (@empty_mandatory_fields || @$invalidformfields || $conflicting_attribute) {
83
        $template->param(
100
        $template->param(
84
            empty_mandatory_fields => \@empty_mandatory_fields,
101
            empty_mandatory_fields => \@empty_mandatory_fields,
85
            invalid_form_fields    => $invalidformfields,
102
            invalid_form_fields    => $invalidformfields,
86
            borrower               => \%borrower
103
            borrower               => \%borrower
87
        );
104
        );
105
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );
88
    }
106
    }
89
    elsif (
107
    elsif (
90
        md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') )
108
        md5_base64( $cgi->param('captcha') ) ne $cgi->param('captcha_digest') )
Lines 93-98 if ( $action eq 'create' ) { Link Here
93
            failed_captcha => 1,
111
            failed_captcha => 1,
94
            borrower       => \%borrower
112
            borrower       => \%borrower
95
        );
113
        );
114
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );
96
    }
115
    }
97
    else {
116
    else {
98
        if (
117
        if (
Lines 150-155 if ( $action eq 'create' ) { Link Here
150
                  C4::Context->preference('OpacPasswordChange') );
169
                  C4::Context->preference('OpacPasswordChange') );
151
170
152
            my ( $borrowernumber, $password ) = AddMember_Opac(%borrower);
171
            my ( $borrowernumber, $password ) = AddMember_Opac(%borrower);
172
            C4::Members::Attributes::SetBorrowerAttributes( $borrowernumber, $attributes );
153
            C4::Form::MessagingPreferences::handle_form_action($cgi, { borrowernumber => $borrowernumber }, $template, 1, C4::Context->preference('PatronSelfRegistrationDefaultCategory') ) if $borrowernumber && C4::Context->preference('EnhancedMessagingPreferences');
173
            C4::Form::MessagingPreferences::handle_form_action($cgi, { borrowernumber => $borrowernumber }, $template, 1, C4::Context->preference('PatronSelfRegistrationDefaultCategory') ) if $borrowernumber && C4::Context->preference('EnhancedMessagingPreferences');
154
174
155
            $template->param( password_cleartext => $password );
175
            $template->param( password_cleartext => $password );
Lines 172-183 elsif ( $action eq 'update' ) { Link Here
172
      CheckMandatoryFields( \%borrower_changes, $action );
192
      CheckMandatoryFields( \%borrower_changes, $action );
173
    my $invalidformfields = CheckForInvalidFields(\%borrower);
193
    my $invalidformfields = CheckForInvalidFields(\%borrower);
174
194
175
    if (@empty_mandatory_fields || @$invalidformfields) {
195
    if (@empty_mandatory_fields || @$invalidformfields || $conflicting_attribute) {
176
        $template->param(
196
        $template->param(
177
            empty_mandatory_fields => \@empty_mandatory_fields,
197
            empty_mandatory_fields => \@empty_mandatory_fields,
178
            invalid_form_fields    => $invalidformfields,
198
            invalid_form_fields    => $invalidformfields,
179
            borrower               => \%borrower
199
            borrower               => \%borrower
180
        );
200
        );
201
        $template->param( patron_attribute_classes => GeneratePatronAttributesForm( undef, $attributes ) );
181
202
182
        $template->param( action => 'edit' );
203
        $template->param( action => 'edit' );
183
    }
204
    }
Lines 215-228 elsif ( $action eq 'update' ) { Link Here
215
elsif ( $action eq 'edit' ) {    #Display logged in borrower's data
236
elsif ( $action eq 'edit' ) {    #Display logged in borrower's data
216
    my $borrower = GetMember( borrowernumber => $borrowernumber );
237
    my $borrower = GetMember( borrowernumber => $borrowernumber );
217
238
218
    if (C4::Context->preference('ExtendedPatronAttributes')) {
219
        my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber, 'opac');
220
        if (scalar(@$attributes) > 0) {
221
            $borrower->{ExtendedPatronAttributes} = 1;
222
            $borrower->{patron_attributes} = $attributes;
223
        }
224
    }
225
226
    $template->param(
239
    $template->param(
227
        borrower => $borrower, );
240
        borrower => $borrower, );
228
241
Lines 235-240 elsif ( $action eq 'edit' ) { #Display logged in borrower's data Link Here
235
        }
248
        }
236
    }
249
    }
237
250
251
    $template->param( patron_attribute_classes => GeneratePatronAttributesForm( $borrower ) );
252
} else {
253
    $template->param( patron_attribute_classes => GeneratePatronAttributesForm() );
238
}
254
}
239
255
240
my $captcha = random_string("CCCCC");
256
my $captcha = random_string("CCCCC");
Lines 361-363 sub DelEmptyFields { Link Here
361
377
362
    return %borrower;
378
    return %borrower;
363
}
379
}
364
- 
380
381
sub GeneratePatronAttributesForm {
382
    my ( $borrower, $entered_attributes ) = @_;
383
384
    use Data::Dumper; warn Dumper( $entered_attributes );
385
386
    # Get all attribute types and the values for this patron (if applicable)
387
    my @types = C4::Members::AttributeTypes::GetAttributeTypes();
388
389
    if (scalar(@types) == 0) {
390
        return [];
391
    }
392
393
    my %attr_values = ();
394
395
    if ( $borrower ) {
396
        my $attributes = C4::Members::Attributes::GetBorrowerAttributes($borrowernumber);
397
398
        # Remap the patron's attributes into a hash of arrayrefs per attribute (depends on
399
        # autovivification)
400
        foreach my $attr (@$attributes) {
401
            push @{ $attr_values{ $attr->{code} } }, $attr;
402
        }
403
    }
404
405
    if ( $entered_attributes ) {
406
        foreach my $attr (@$entered_attributes) {
407
            push @{ $attr_values{ $attr->{code} } }, $attr;
408
        }
409
    }
410
411
    # Find all existing classes
412
    my @classes = uniq( map { $_->{class} } @types );
413
    @classes = sort @classes;
414
    my %items_by_class;
415
416
    foreach my $attr_type_desc (@types) {
417
        my $attr_type = C4::Members::AttributeTypes->fetch( $attr_type_desc->{code} );
418
        # Make sure this attribute should be displayed in the OPAC
419
        next unless ( $attr_type->opac_display() );
420
        # Then, make sure it either has values or is editable
421
        next unless ( $attr_values{ $attr_type->code() } || $attr_type->opac_editable() );
422
423
        push @{ $items_by_class{ $attr_type->class() } }, {
424
            type => $attr_type,
425
            # If editable, make sure there's at least one empty entry, to make the template's job easier
426
            values => $attr_values{ $attr_type->code() } || [{}]
427
        };
428
    }
429
430
    use Data::Dumper; warn Dumper( \%items_by_class );
431
432
    # Finally, build a list of containing classes
433
    my @class_loop;
434
    foreach my $class (@classes) {
435
        next unless ( $items_by_class{$class} );
436
437
        my $lib = GetAuthorisedValueByCode( 'PA_CLASS', $class, 1 ) || $class;
438
        push @class_loop, {
439
            class => $class,
440
            items => $items_by_class{$class},
441
            lib   => $lib,
442
        };
443
    }
444
445
    return \@class_loop;
446
}
447
448
sub ParsePatronAttributes {
449
    my ( $cgi ) = @_;
450
451
    my @codes = $cgi->param('patron_attribute_code');
452
    my @values = $cgi->param('patron_attribute_value');
453
    my @passwords = $cgi->param('patron_attribute_password');
454
455
    my $ea = each_array( @codes, @values, @passwords );
456
    my @attributes;
457
    my %dups = ();
458
459
    while ( my ( $code, $value, $password ) = $ea->() ) {
460
        next unless defined($value) and $value ne '';
461
        next if exists $dups{$code}->{$value};
462
        $dups{$code}->{$value} = 1;
463
464
        push @attributes, { code => $code, value => $value, password => $password };
465
    }
466
467
    return \@attributes;
468
}

Return to bug 13757