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

(-)a/C4/Auth_with_ldap.pm (-4 / +6 lines)
Lines 233-240 sub checkpw_ldap { Link Here
233
        return 0;   # B2, D2
233
        return 0;   # B2, D2
234
    }
234
    }
235
    if (C4::Context->preference('ExtendedPatronAttributes') && $borrowernumber && ($config{update} ||$config{replicate})) {
235
    if (C4::Context->preference('ExtendedPatronAttributes') && $borrowernumber && ($config{update} ||$config{replicate})) {
236
        foreach my $attribute_type ( C4::Members::AttributeTypes::GetAttributeTypes() ) {
236
        my $attribute_types = Koha::Patron::Attribute::Types->filter_by_branch_limitations;
237
            my $code = $attribute_type->{code};
237
        while ( my $attribute_type = $attribute_types->next ) {
238
            my $code = $attribute_type->code;
238
            unless (exists($borrower{$code}) && $borrower{$code} !~ m/^\s*$/ ) {
239
            unless (exists($borrower{$code}) && $borrower{$code} !~ m/^\s*$/ ) {
239
                next;
240
                next;
240
            }
241
            }
Lines 375-382 sub update_local { Link Here
375
    # skip extended patron attributes in 'borrowers' attribute update
376
    # skip extended patron attributes in 'borrowers' attribute update
376
    my @keys = keys %$borrower;
377
    my @keys = keys %$borrower;
377
    if (C4::Context->preference('ExtendedPatronAttributes')) {
378
    if (C4::Context->preference('ExtendedPatronAttributes')) {
378
        foreach my $attribute_type ( C4::Members::AttributeTypes::GetAttributeTypes() ) {
379
        my $attribute_types = Koha::Patron::Attribute::Types->filter_by_branch_limitations;
379
           my $code = $attribute_type->{code};
380
        while ( my $attribute_type = $attribute_types->next ) {
381
           my $code = $attribute_type->code;
380
           @keys = grep { $_ ne $code } @keys;
382
           @keys = grep { $_ ne $code } @keys;
381
           $debug and printf STDERR "ignoring extended patron attribute '%s' in update_local()\n", $code;
383
           $debug and printf STDERR "ignoring extended patron attribute '%s' in update_local()\n", $code;
382
        }
384
        }
(-)a/C4/Members/AttributeTypes.pm (-44 lines)
Lines 28-35 C4::Members::AttributeTypes - mananage extended patron attribute types Link Here
28
28
29
=head1 SYNOPSIS
29
=head1 SYNOPSIS
30
30
31
  my @attribute_types = C4::Members::AttributeTypes::GetAttributeTypes();
32
33
  my $attr_type = C4::Members::AttributeTypes->new($code, $description);
31
  my $attr_type = C4::Members::AttributeTypes->new($code, $description);
34
  $attr_type->code($code);
32
  $attr_type->code($code);
35
  $attr_type->description($description);
33
  $attr_type->description($description);
Lines 47-94 C4::Members::AttributeTypes - mananage extended patron attribute types Link Here
47
45
48
=head1 FUNCTIONS
46
=head1 FUNCTIONS
49
47
50
=head2 GetAttributeTypes
51
52
  my @attribute_types = C4::Members::AttributeTypes::GetAttributeTypes($all_fields);
53
54
Returns an array of hashrefs of each attribute type defined
55
in the database.  The array is sorted by code.  Each hashref contains
56
at least the following fields:
57
58
 - code
59
 - description
60
61
If $all_fields is true, then each hashref also contains the other fields from borrower_attribute_types.
62
63
=cut
64
65
sub GetAttributeTypes {
66
    my $all    = @_   ? shift : 0;
67
    my $no_branch_limit = @_ ? shift : 0;
68
    my $branch_limit = $no_branch_limit
69
        ? 0
70
        : C4::Context->userenv ? C4::Context->userenv->{"branch"} : 0;
71
    my $select = $all ? '*'   : 'DISTINCT(code), description, class';
72
73
    my $dbh = C4::Context->dbh;
74
    my $query = "SELECT $select FROM borrower_attribute_types";
75
    $query .= qq{
76
        LEFT JOIN borrower_attribute_types_branches ON bat_code = code
77
        WHERE b_branchcode = ? OR b_branchcode IS NULL
78
    } if $branch_limit;
79
    $query .= " ORDER BY code";
80
    my $sth    = $dbh->prepare($query);
81
    $sth->execute( $branch_limit ? $branch_limit : () );
82
    my $results = $sth->fetchall_arrayref({});
83
    $sth->finish;
84
    return @$results;
85
}
86
87
sub GetAttributeTypes_hashref {
88
    my %hash = map {$_->{code} => $_} GetAttributeTypes(@_);
89
    return \%hash;
90
}
91
92
=head1 METHODS 
48
=head1 METHODS 
93
49
94
  my $attr_type = C4::Members::AttributeTypes->new($code, $description);
50
  my $attr_type = C4::Members::AttributeTypes->new($code, $description);
(-)a/C4/Members/Attributes.pm (-3 / +4 lines)
Lines 22-28 use warnings; Link Here
22
22
23
use Text::CSV;      # Don't be tempted to use Text::CSV::Unicode -- even in binary mode it fails.
23
use Text::CSV;      # Don't be tempted to use Text::CSV::Unicode -- even in binary mode it fails.
24
use C4::Context;
24
use C4::Context;
25
use C4::Members::AttributeTypes;
25
26
use Koha::Patron::Attribute::Types;
26
27
27
use vars qw(@ISA @EXPORT_OK @EXPORT %EXPORT_TAGS);
28
use vars qw(@ISA @EXPORT_OK @EXPORT %EXPORT_TAGS);
28
our ($csv, $AttributeTypes);
29
our ($csv, $AttributeTypes);
Lines 110-116 The third option specifies whether repeatable codes are clobbered or collected. Link Here
110
111
111
Returns one reference to (merged) array of hashref.
112
Returns one reference to (merged) array of hashref.
112
113
113
Caches results of C4::Members::AttributeTypes::GetAttributeTypes_hashref(1) for efficiency.
114
Caches results of attribute types for efficiency. # FIXME That is very bad and can cause side-effects undef plack
114
115
115
=cut
116
=cut
116
117
Lines 118-124 sub extended_attributes_merge { Link Here
118
    my $old = shift or return;
119
    my $old = shift or return;
119
    my $new = shift or return $old;
120
    my $new = shift or return $old;
120
    my $keep = @_ ? shift : 0;
121
    my $keep = @_ ? shift : 0;
121
    $AttributeTypes or $AttributeTypes = C4::Members::AttributeTypes::GetAttributeTypes_hashref(1);
122
    $AttributeTypes or $AttributeTypes = Koha::Patron::Attribute::Types->search->unblessed;
122
    my @merged = @$old;
123
    my @merged = @$old;
123
    foreach my $att (@$new) {
124
    foreach my $att (@$new) {
124
        unless ($att->{code}) {
125
        unless ($att->{code}) {
(-)a/Koha/Template/Plugin/Branches.pm (-5 / +18 lines)
Lines 58-63 sub GetURL { Link Here
58
sub all {
58
sub all {
59
    my ( $self, $params ) = @_;
59
    my ( $self, $params ) = @_;
60
    my $selected = $params->{selected};
60
    my $selected = $params->{selected};
61
    my $selecteds = $params->{selecteds};
61
    my $unfiltered = $params->{unfiltered} || 0;
62
    my $unfiltered = $params->{unfiltered} || 0;
62
    my $search_params = $params->{search_params} || {};
63
    my $search_params = $params->{search_params} || {};
63
64
Lines 69-79 sub all { Link Here
69
      ? Koha::Libraries->search( $search_params, { order_by => ['branchname'] } )->unblessed
70
      ? Koha::Libraries->search( $search_params, { order_by => ['branchname'] } )->unblessed
70
      : Koha::Libraries->search_filtered( $search_params, { order_by => ['branchname'] } )->unblessed;
71
      : Koha::Libraries->search_filtered( $search_params, { order_by => ['branchname'] } )->unblessed;
71
72
72
    for my $l ( @$libraries ) {
73
    if (defined $selecteds) {
73
        if (       defined $selected and $l->{branchcode} eq $selected
74
        # For a select multiple, must be a Koha::Libraries
74
            or not defined $selected and C4::Context->userenv and $l->{branchcode} eq ( C4::Context->userenv->{branch} // q{} )
75
        my @selected_branchcodes = $selecteds ? $selecteds->get_column( ['branchcode'] ) : ();
75
        ) {
76
        $libraries = [ map {
76
            $l->{selected} = 1;
77
            my $l = $_;
78
            $l->{selected} = 1
79
              if grep { $_ eq $l->{branchcode} } @selected_branchcodes;
80
            $l;
81
        } @$libraries ];
82
    }
83
    else {
84
        for my $l ( @$libraries ) {
85
            if (       defined $selected and $l->{branchcode} eq $selected
86
                or not defined $selected and C4::Context->userenv and $l->{branchcode} eq ( C4::Context->userenv->{branch} // q{} )
87
            ) {
88
                $l->{selected} = 1;
89
            }
77
        }
90
        }
78
    }
91
    }
79
92
(-)a/admin/patron-attr-types.pl (-84 / +10 lines)
Lines 29-34 use C4::Context; Link Here
29
use C4::Output;
29
use C4::Output;
30
use C4::Koha;
30
use C4::Koha;
31
use C4::Members::AttributeTypes;
31
use C4::Members::AttributeTypes;
32
use Koha::Patron::Attribute::Types;
32
33
33
use Koha::AuthorisedValues;
34
use Koha::AuthorisedValues;
34
use Koha::Libraries;
35
use Koha::Libraries;
Lines 86-108 exit 0; Link Here
86
sub add_attribute_type_form {
87
sub add_attribute_type_form {
87
    my $template = shift;
88
    my $template = shift;
88
89
89
    my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
90
    my @branches_loop;
91
    foreach my $branch (@$branches) {
92
        push @branches_loop, {
93
            branchcode => $branch->{branchcode},
94
            branchname => $branch->{branchname},
95
        };
96
    }
97
98
    my $patron_categories = Koha::Patron::Categories->search_limited({}, {order_by => ['description']});
90
    my $patron_categories = Koha::Patron::Categories->search_limited({}, {order_by => ['description']});
99
    $template->param(
91
    $template->param(
100
        attribute_type_form => 1,
92
        attribute_type_form => 1,
101
        confirm_op => 'add_attribute_type_confirmed',
93
        confirm_op => 'add_attribute_type_confirmed',
102
        categories => $patron_categories,
94
        categories => $patron_categories,
103
        branches_loop => \@branches_loop,
104
    );
95
    );
105
    $template->param(classes_val_loop => GetAuthorisedValues( 'PA_CLASS'));
106
}
96
}
107
97
108
sub error_add_attribute_type_form {
98
sub error_add_attribute_type_form {
Lines 110-134 sub error_add_attribute_type_form { Link Here
110
100
111
    $template->param(description => scalar $input->param('description'));
101
    $template->param(description => scalar $input->param('description'));
112
102
113
    if ($input->param('repeatable')) {
114
        $template->param(repeatable_checked => 1);
115
    }
116
    if ($input->param('unique_id')) {
117
        $template->param(unique_id_checked => 1);
118
    }
119
    if ($input->param('opac_display')) {
120
        $template->param(opac_display_checked => 1);
121
    }
122
    if ($input->param('opac_editable')) {
123
        $template->param(opac_editable_checked => 1);
124
    }
125
    if ($input->param('staff_searchable')) {
126
        $template->param(staff_searchable_checked => 1);
127
    }
128
    if ($input->param('display_checkout')) {
129
        $template->param(display_checkout_checked => 'checked="checked"');
130
    }
131
132
    $template->param( category_code => scalar $input->param('category_code') );
103
    $template->param( category_code => scalar $input->param('category_code') );
133
    $template->param( class => scalar $input->param('class') );
104
    $template->param( class => scalar $input->param('class') );
134
105
Lines 154-159 sub add_update_attribute_type { Link Here
154
        my $existing = C4::Members::AttributeTypes->fetch($code);
125
        my $existing = C4::Members::AttributeTypes->fetch($code);
155
        if (defined($existing)) {
126
        if (defined($existing)) {
156
            $template->param(duplicate_code_error => $code);
127
            $template->param(duplicate_code_error => $code);
128
            # FIXME Regression here
129
            # Form will not be refilled with entered values on error
157
            error_add_attribute_type_form($template);
130
            error_add_attribute_type_form($template);
158
            return 0;
131
            return 0;
159
        }
132
        }
Lines 231-283 sub edit_attribute_type_form { Link Here
231
    my $template = shift;
204
    my $template = shift;
232
    my $code = shift;
205
    my $code = shift;
233
206
234
    my $attr_type = C4::Members::AttributeTypes->fetch($code);
207
    my $attr_type = Koha::Patron::Attribute::Types->find($code);
235
208
    $template->param(attribute_type => $attr_type);
236
    $template->param(code => $code);
237
    $template->param(description => $attr_type->description());
238
    $template->param(class => $attr_type->class());
239
240
    if ($attr_type->repeatable()) {
241
        $template->param(repeatable_checked => 1);
242
    }
243
    $template->param(repeatable_disabled => 1);
244
    if ($attr_type->unique_id()) {
245
        $template->param(unique_id_checked => 1);
246
    }
247
    $template->param(unique_id_disabled => 1);
248
    if ($attr_type->opac_display()) {
249
        $template->param(opac_display_checked => 1);
250
    }
251
    if ($attr_type->opac_editable()) {
252
        $template->param(opac_editable_checked => 1);
253
    }
254
    if ($attr_type->staff_searchable()) {
255
        $template->param(staff_searchable_checked => 1);
256
    }
257
    if ($attr_type->display_checkout()) {
258
        $template->param(display_checkout_checked => 'checked="checked"');
259
    }
260
    $template->param( authorised_value_category => $attr_type->authorised_value_category() );
261
    $template->param(classes_val_loop => GetAuthorisedValues( 'PA_CLASS' ));
262
263
    my $branches = Koha::Libraries->search( {}, { order_by => ['branchname'] } )->unblessed;
264
    my @branches_loop;
265
    my $selected_branches = $attr_type->branches;
266
    foreach my $branch (@$branches) {
267
        my $selected = ( grep {$_->{branchcode} eq $branch->{branchcode}} @$selected_branches ) ? 1 : 0;
268
        push @branches_loop, {
269
            branchcode => $branch->{branchcode},
270
            branchname => $branch->{branchname},
271
            selected => $selected,
272
        };
273
    }
274
    $template->param( branches_loop => \@branches_loop );
275
276
    $template->param(
277
        category_code        => $attr_type->category_code,
278
        category_class       => $attr_type->class,
279
        category_description => $attr_type->category_description,
280
    );
281
209
282
    my $patron_categories = Koha::Patron::Categories->search({}, {order_by => ['description']});
210
    my $patron_categories = Koha::Patron::Categories->search({}, {order_by => ['description']});
283
    $template->param(
211
    $template->param(
Lines 292-309 sub edit_attribute_type_form { Link Here
292
sub patron_attribute_type_list {
220
sub patron_attribute_type_list {
293
    my $template = shift;
221
    my $template = shift;
294
222
295
    my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes( 1, 1 );
223
    my @attr_types = Koha::Patron::Attribute::Types->search->as_list;
296
224
297
    my @classes = uniq( map { $_->{class} } @attr_types );
225
    my @classes = uniq( map { $_->class } @attr_types );
298
    @classes = sort @classes;
226
    @classes = sort @classes;
299
227
300
    my @attributes_loop;
228
    my @attributes_loop;
229
    # FIXME This is not efficient and should be improved
301
    for my $class (@classes) {
230
    for my $class (@classes) {
302
        my ( @items, $branches );
231
        my @items;
303
        for my $attr (@attr_types) {
232
        for my $attr (@attr_types) {
304
            next if $attr->{class} ne $class;
233
            next if $attr->class ne $class;
305
            my $attr_type = C4::Members::AttributeTypes->fetch($attr->{code});
306
            $attr->{branches} = $attr_type->branches;
307
            push @items, $attr;
234
            push @items, $attr;
308
        }
235
        }
309
        my $av = Koha::AuthorisedValues->search({ category => 'PA_CLASS', authorised_value => $class });
236
        my $av = Koha::AuthorisedValues->search({ category => 'PA_CLASS', authorised_value => $class });
Lines 312-318 sub patron_attribute_type_list { Link Here
312
            class => $class,
239
            class => $class,
313
            items => \@items,
240
            items => \@items,
314
            lib   => $lib,
241
            lib   => $lib,
315
            branches => $branches,
316
        };
242
        };
317
    }
243
    }
318
    $template->param(available_attribute_types => \@attributes_loop);
244
    $template->param(available_attribute_types => \@attributes_loop);
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/patron-attr-types.tt (-60 / +36 lines)
Lines 1-6 Link Here
1
[% USE raw %]
1
[% USE raw %]
2
[% USE Asset %]
2
[% USE Asset %]
3
[% USE AuthorisedValues %]
3
[% USE AuthorisedValues %]
4
[% USE Branches %]
5
[% USE scalar %]
4
[% SET footerjs = 1 %]
6
[% SET footerjs = 1 %]
5
[% INCLUDE 'doc-head-open.inc' %]
7
[% INCLUDE 'doc-head-open.inc' %]
6
<title>Koha &rsaquo; Administration &rsaquo; Patron attribute types
8
<title>Koha &rsaquo; Administration &rsaquo; Patron attribute types
Lines 60-69 Link Here
60
  <fieldset class="rows">
62
  <fieldset class="rows">
61
    <ol>
63
    <ol>
62
      <li>
64
      <li>
63
          [% IF ( edit_attribute_type ) %]
65
          [% IF attribute_type %]
64
		  <span class="label">Patron attribute type code: </span>
66
            <span class="label">Patron attribute type code: </span>
65
            <input type="hidden" name="code" value="[% code | html %]" />
67
            <input type="hidden" name="code" value="[% attribute_type.code |html %]" />
66
            [% code | html %]
68
            [% attribute_type.code |html %]
67
          [% ELSE %]
69
          [% ELSE %]
68
              <label for="code" class="required">Patron attribute type code: </label>
70
              <label for="code" class="required">Patron attribute type code: </label>
69
              <input type="text" id="code" name="code" required="required" class="required" size="10" maxlength="10" />
71
              <input type="text" id="code" name="code" required="required" class="required" size="10" maxlength="10" />
Lines 71-115 Link Here
71
          [% END %]
73
          [% END %]
72
       </li>
74
       </li>
73
       <li><label for="description" class="required">Description: </label>
75
       <li><label for="description" class="required">Description: </label>
74
           <input type="text" id="description" name="description" required="required" class="required" size="50" maxlength="250" value="[% description | html %]" />
76
           <input type="text" id="description" name="description" required="required" class="required" size="50" maxlength="250" value="[% attribute_type.description |html %]" />
75
           <span class="required">Required</span>
77
           <span class="required">Required</span>
76
       </li>
78
       </li>
77
       <li><label for="repeatable">Repeatable: </label>
79
       <li><label for="repeatable">Repeatable: </label>
78
            [% IF ( repeatable_checked ) %]
80
            [% IF attribute_type %]
79
              [% IF ( repeatable_disabled ) %]
81
                [% IF attribute_type.repeatable %]
80
                <input type="checkbox" id="repeatable" name="repeatable" checked="checked" disabled="disabled" />
82
                    <input type="checkbox" id="repeatable" name="repeatable" checked="checked" disabled="disabled" />
81
              [% ELSE %]
83
                [% ELSE %]
82
                <input type="checkbox" id="repeatable" name="repeatable" checked="checked" />
84
                    <input type="checkbox" id="repeatable" name="repeatable" disabled="disabled" />
83
              [% END %]
85
                [% END %]
84
            [% ELSE %]
86
            [% ELSE %]
85
              [% IF ( repeatable_disabled ) %]
86
                <input type="checkbox" id="repeatable" name="repeatable" disabled="disabled" />
87
              [% ELSE %]
88
                <input type="checkbox" id="repeatable" name="repeatable" />
87
                <input type="checkbox" id="repeatable" name="repeatable" />
89
              [% END %]
90
            [% END %]
88
            [% END %]
91
            <span>Check to let a patron record have multiple values of this attribute.  
89
            <span>Check to let a patron record have multiple values of this attribute.
92
                  This setting cannot be changed after an attribute is defined.</span>
90
                  This setting cannot be changed after an attribute is defined.</span>
93
       </li>
91
       </li>
94
       <li><label for="unique_id">Unique identifier: </label>
92
       <li><label for="unique_id">Unique identifier: </label>
95
            [% IF ( unique_id_checked ) %]
93
            [% IF attribute_type %]
96
              [% IF ( unique_id_disabled ) %]
94
                [% IF attribute_type.unique_id %]
97
                <input type="checkbox" id="unique_id" name="unique_id" checked="checked" disabled="disabled" />
95
                    <input type="checkbox" id="unique_id" name="unique_id" checked="checked" disabled="disabled" />
98
              [% ELSE %]
96
                [% ELSE %]
99
                <input type="checkbox" id="unique_id" name="unique_id" checked="checked" />
97
                    <input type="checkbox" id="unique_id" name="unique_id" disabled="disabled" />
100
              [% END %]
98
                [% END %]
101
            [% ELSE %]
99
            [% ELSE %]
102
              [% IF ( unique_id_disabled ) %]
103
                <input type="checkbox" id="unique_id" name="unique_id" disabled="disabled" />
104
              [% ELSE %]
105
                <input type="checkbox" id="unique_id" name="unique_id" />
100
                <input type="checkbox" id="unique_id" name="unique_id" />
106
              [% END %]
107
            [% END %]
101
            [% END %]
108
            <span>If checked, attribute will be a unique identifier &mdash; if a value is given to a patron record, the same value
102
            <span>If checked, attribute will be a unique identifier &mdash; if a value is given to a patron record, the same value
109
                  cannot be given to a different record.  This setting cannot be changed after an attribute is defined.</span>
103
                  cannot be given to a different record.  This setting cannot be changed after an attribute is defined.</span>
110
       </li>
104
       </li>
111
       <li><label for="opac_display">Display in OPAC: </label>
105
       <li><label for="opac_display">Display in OPAC: </label>
112
          [% IF ( opac_display_checked ) %]
106
          [% IF attribute_type AND attribute_type.opac_display %]
113
            <input type="checkbox" id="opac_display" name="opac_display" checked="checked" />
107
            <input type="checkbox" id="opac_display" name="opac_display" checked="checked" />
114
          [% ELSE %]
108
          [% ELSE %]
115
            <input type="checkbox" id="opac_display" name="opac_display" />
109
            <input type="checkbox" id="opac_display" name="opac_display" />
Lines 117-123 Link Here
117
            <span>Check to display this attribute on a patron's details page in the OPAC.</span>
111
            <span>Check to display this attribute on a patron's details page in the OPAC.</span>
118
       </li>
112
       </li>
119
       <li><label for="opac_editable">Editable in OPAC: </label>
113
       <li><label for="opac_editable">Editable in OPAC: </label>
120
          [% IF ( opac_editable_checked ) %]
114
          [% IF attribute_type AND attribute_type.opac_editable %]
121
            <input type="checkbox" id="opac_editable" name="opac_editable" checked="checked" />
115
            <input type="checkbox" id="opac_editable" name="opac_editable" checked="checked" />
122
          [% ELSE %]
116
          [% ELSE %]
123
            <input type="checkbox" id="opac_editable" name="opac_editable" />
117
            <input type="checkbox" id="opac_editable" name="opac_editable" />
Lines 125-131 Link Here
125
            <span>Check to allow patrons to edit this attribute from their details page in the OPAC. (Requires above, does not work with <a href="/cgi-bin/koha/admin/preferences.pl?op=search&amp;searchfield=PatronSelfRegistrationVerifyByEmail" target="_blank">PatronSelfRegistrationVerifyByEmail</a>.)</span>
119
            <span>Check to allow patrons to edit this attribute from their details page in the OPAC. (Requires above, does not work with <a href="/cgi-bin/koha/admin/preferences.pl?op=search&amp;searchfield=PatronSelfRegistrationVerifyByEmail" target="_blank">PatronSelfRegistrationVerifyByEmail</a>.)</span>
126
       </li>
120
       </li>
127
       <li><label for="staff_searchable">Searchable: </label>
121
       <li><label for="staff_searchable">Searchable: </label>
128
          [% IF ( staff_searchable_checked ) %]
122
          [% IF attribute_type AND attribute_type.staff_searchable %]
129
            <input type="checkbox" id="staff_searchable" name="staff_searchable" checked="checked" />
123
            <input type="checkbox" id="staff_searchable" name="staff_searchable" checked="checked" />
130
          [% ELSE %]
124
          [% ELSE %]
131
            <input type="checkbox" id="staff_searchable" name="staff_searchable" />
125
            <input type="checkbox" id="staff_searchable" name="staff_searchable" />
Lines 133-139 Link Here
133
            <span>Check to make this attribute staff_searchable in the staff patron search.</span>
127
            <span>Check to make this attribute staff_searchable in the staff patron search.</span>
134
       </li>
128
       </li>
135
       <li><label for="display_checkout">Display in check-out: </label>
129
       <li><label for="display_checkout">Display in check-out: </label>
136
            [% IF display_checkout_checked %]
130
            [% IF attribute_type AND attribute_type.display_checkout %]
137
                <input type="checkbox" id="display_checkout" name="display_checkout" checked="checked" />
131
                <input type="checkbox" id="display_checkout" name="display_checkout" checked="checked" />
138
	    [% ELSE %]
132
	    [% ELSE %]
139
	        <input type="checkbox" id="display_checkout" name="display_checkout" />
133
	        <input type="checkbox" id="display_checkout" name="display_checkout" />
Lines 144-150 Link Here
144
        <li><label for="authorised_value_category">Authorized value category: </label>
138
        <li><label for="authorised_value_category">Authorized value category: </label>
145
            <select name="authorised_value_category" id="authorised_value_category">
139
            <select name="authorised_value_category" id="authorised_value_category">
146
                <option value=""></option>
140
                <option value=""></option>
147
                [% PROCESS options_for_authorised_value_categories authorised_value_categories => AuthorisedValues.GetCategories( selected => authorised_value_category ) %]
141
                [% PROCESS options_for_authorised_value_categories authorised_value_categories => AuthorisedValues.GetCategories( selected => attribute_type.authorised_value_category ) %]
148
            </select>
142
            </select>
149
            <span>Authorized value category; if one is selected, the patron record input page will only allow values 
143
            <span>Authorized value category; if one is selected, the patron record input page will only allow values 
150
                  to be chosen from the authorized value list.  However, an authorized value list is not 
144
                  to be chosen from the authorized value list.  However, an authorized value list is not 
Lines 153-165 Link Here
153
        <li><label for="branches">Branches limitation: </label>
147
        <li><label for="branches">Branches limitation: </label>
154
            <select id="branches" name="branches" multiple size="10">
148
            <select id="branches" name="branches" multiple size="10">
155
                <option value="">All branches</option>
149
                <option value="">All branches</option>
156
                [% FOREACH branch IN branches_loop %]
150
                [% PROCESS options_for_libraries libraries => Branches.all( selecteds => attribute_type.library_limits ) %]
157
                  [% IF ( branch.selected ) %]
158
                    <option selected="selected" value="[% branch.branchcode | html %]">[% branch.branchname | html %]</option>
159
                  [% ELSE %]
160
                    <option value="[% branch.branchcode | html %]">[% branch.branchname | html %]</option>
161
                  [% END %]
162
                [% END %]
163
            </select>
151
            </select>
164
            <span>Select All if this attribute type must to be displayed all the time. Otherwise select libraries you want to associate with this value.
152
            <span>Select All if this attribute type must to be displayed all the time. Otherwise select libraries you want to associate with this value.
165
            </span>
153
            </span>
Lines 169-195 Link Here
169
            <select name="category_code" id="category">
157
            <select name="category_code" id="category">
170
                <option value=""></option>
158
                <option value=""></option>
171
                [% FOREACH cat IN categories %]
159
                [% FOREACH cat IN categories %]
172
                    [% IF ( cat.categorycode == category_code ) %]<option value="[% cat.categorycode | html %]" selected="selected">[% cat.description | html %]</option>[% ELSE %]<option value="[% cat.categorycode | html %]">[% cat.description | html %]</option>[% END %]
160
                    [% IF ( cat.categorycode == attribute_type.category_code ) %]<option value="[% cat.categorycode | html %]" selected="selected">[% cat.description |html %]</option>[% ELSE %]<option value="[% cat.categorycode | html %]">[% cat.description |html %]</option>[% END %]
173
                [% END %]
161
                [% END %]
174
            </select>
162
            </select>
175
            <span>Choose one to limit this attribute to one patron type. Please leave blank if you want these attributes to be available for all types of patrons.</span>
163
            <span>Choose one to limit this attribute to one patron type. Please leave blank if you want these attributes to be available for all types of patrons.</span>
176
        </li>
164
        </li>
177
        <li>
165
        <li>
178
            <label for="class">Class: </label>
166
            <label for="class">Class: </label>
179
            <select name="class" id="class">
167
            [% PROCESS 'av-build-dropbox.inc' name="class", category="PA_CLASS" default=attribute_type.class %]
180
                <option value=""></option>
181
                [% FOREACH class IN classes_val_loop %]
182
                    [% IF class.authorised_value == category_class %]
183
                        <option value="[% class.authorised_value | html %]" selected="selected">
184
                            [% class.lib | html %]
185
                        </option>
186
                    [% ELSE %]
187
                        <option value="[% class.authorised_value | html %]" >
188
                            [% class.lib | html %]
189
                        </option>
190
                    [% END %]
191
                [% END %]
192
            </select>
193
            <span>Group attributes types with a block title (based on authorized values category 'PA_CLASS')</span>
168
            <span>Group attributes types with a block title (based on authorized values category 'PA_CLASS')</span>
194
        </li>
169
        </li>
195
    </ol>
170
    </ol>
Lines 259-274 Link Here
259
            <td>[% item.code | html %]</td>
234
            <td>[% item.code | html %]</td>
260
            <td>[% item.description | html %]</td>
235
            <td>[% item.description | html %]</td>
261
            <td>
236
            <td>
262
                [% IF ( item.branches && item.branches.size > 0 ) %]
237
                [% SET libraries = item.library_limits %]
238
                [% IF ( libraries && libraries.count > 0 ) %]
263
                    [% branches_str = "" %]
239
                    [% branches_str = "" %]
264
                    [% FOREACH branch IN item.branches %]
240
                    [% FOREACH branch IN libraries %]
265
                        [% branches_str = branches_str _ " " _ branch.branchname _ "(" _ branch.branchcode _ ")" %]
241
                        [% branches_str = branches_str _ " " _ branch.branchname _ "(" _ branch.branchcode _ ")" %]
266
                    [% END %]
242
                    [% END %]
267
                    <span title="[% branches_str | html %]">
243
                    <span title="[% branches_str | html %]">
268
                        [% IF item.branches.size > 1 %]
244
                        [% IF libraries.count > 1 %]
269
                            [% item.branches.size | html %] branches limitations
245
                            [% libraries.count | html %] branches limitations
270
                        [% ELSE %]
246
                        [% ELSE %]
271
                            [% item.branches.size | html %] branch limitation
247
                            [% libraries.count | html %] branch limitation
272
                        [% END %]
248
                        [% END %]
273
                    </span>
249
                    </span>
274
                [% ELSE %]
250
                [% ELSE %]
Lines 276-283 Link Here
276
                [% END %]
252
                [% END %]
277
            </td>
253
            </td>
278
            <td class="actions">
254
            <td class="actions">
279
              <a class="btn btn-default btn-xs" href="[% item.script_name | url %]?op=edit_attribute_type&amp;code=[% item.code | uri %]"><i class="fa fa-pencil"></i> Edit</a>
255
              <a class="btn btn-default btn-xs" href="[% script_name | url %]?op=edit_attribute_type&amp;code=[% item.code | uri %]"><i class="fa fa-pencil"></i> Edit</a>
280
              <a class="btn btn-default btn-xs" href="[% item.script_name | url %]?op=delete_attribute_type&amp;code=[% item.code | uri %]"><i class="fa fa-trash"></i> Delete</a>
256
              <a class="btn btn-default btn-xs" href="[% script_name | url %]?op=delete_attribute_type&amp;code=[% item.code | uri %]"><i class="fa fa-trash"></i> Delete</a>
281
            </td>
257
            </td>
282
          </tr>
258
          </tr>
283
        [% END %]
259
        [% END %]
(-)a/members/memberentry.pl (-4 / +4 lines)
Lines 43-48 use Koha::Cities; Link Here
43
use Koha::DateUtils;
43
use Koha::DateUtils;
44
use Koha::Libraries;
44
use Koha::Libraries;
45
use Koha::Patrons;
45
use Koha::Patrons;
46
use Koha::Patron::Attribute::Types;
46
use Koha::Patron::Categories;
47
use Koha::Patron::Categories;
47
use Koha::Patron::HouseboundRole;
48
use Koha::Patron::HouseboundRole;
48
use Koha::Patron::HouseboundRoles;
49
use Koha::Patron::HouseboundRoles;
Lines 854-861 sub patron_attributes_form { Link Here
854
    my $borrowernumber = shift;
855
    my $borrowernumber = shift;
855
    my $op = shift;
856
    my $op = shift;
856
857
857
    my @types = C4::Members::AttributeTypes::GetAttributeTypes();
858
    my $attribute_types = Koha::Patron::Attribute::Types->filter_by_branch_limitations;
858
    if (scalar(@types) == 0) {
859
    if ( $attribute_types->count == 0 ) {
859
        $template->param(no_patron_attribute_types => 1);
860
        $template->param(no_patron_attribute_types => 1);
860
        return;
861
        return;
861
    }
862
    }
Lines 874-881 sub patron_attributes_form { Link Here
874
    my @attribute_loop = ();
875
    my @attribute_loop = ();
875
    my $i = 0;
876
    my $i = 0;
876
    my %items_by_class;
877
    my %items_by_class;
877
    foreach my $type_code (map { $_->{code} } @types) {
878
    while ( my ( $attr_type ) = $attribute_types->next ) {
878
        my $attr_type = C4::Members::AttributeTypes->fetch($type_code);
879
        my $entry = {
879
        my $entry = {
880
            class             => $attr_type->class(),
880
            class             => $attr_type->class(),
881
            code              => $attr_type->code(),
881
            code              => $attr_type->code(),
(-)a/members/moremember.pl (-2 / +3 lines)
Lines 35-40 use C4::Output; Link Here
35
use C4::Members::AttributeTypes;
35
use C4::Members::AttributeTypes;
36
use C4::Form::MessagingPreferences;
36
use C4::Form::MessagingPreferences;
37
use List::MoreUtils qw/uniq/;
37
use List::MoreUtils qw/uniq/;
38
use Koha::Patron::Attribute::Types;
38
use Koha::Patron::Debarments qw(GetDebarments);
39
use Koha::Patron::Debarments qw(GetDebarments);
39
use Koha::Patron::Messages;
40
use Koha::Patron::Messages;
40
use Koha::DateUtils;
41
use Koha::DateUtils;
Lines 154-161 if (C4::Context->preference('ExtendedPatronAttributes')) { Link Here
154
        attributes_loop => \@attributes_loop
155
        attributes_loop => \@attributes_loop
155
    );
156
    );
156
157
157
    my @types = C4::Members::AttributeTypes::GetAttributeTypes();
158
    my $nb_of_attribute_types = Koha::Patron::Attribute::Types->filter_by_branch_limitations->count;
158
    if (scalar(@types) == 0) {
159
    if ( $nb_of_attribute_types == 0 ) {
159
        $template->param(no_patron_attribute_types => 1);
160
        $template->param(no_patron_attribute_types => 1);
160
    }
161
    }
161
}
162
}
(-)a/reports/borrowers_stats.pl (-7 / +6 lines)
Lines 28-38 use C4::Acquisition; Link Here
28
use C4::Output;
28
use C4::Output;
29
use C4::Reports;
29
use C4::Reports;
30
use C4::Circulation;
30
use C4::Circulation;
31
use C4::Members::AttributeTypes;
32
31
33
use Koha::AuthorisedValues;
32
use Koha::AuthorisedValues;
34
use Koha::DateUtils;
33
use Koha::DateUtils;
35
use Koha::Libraries;
34
use Koha::Libraries;
35
use Koha::Patron::Attribute::Types;
36
use Koha::Patron::Categories;
36
use Koha::Patron::Categories;
37
37
38
use Date::Calc qw(
38
use Date::Calc qw(
Lines 157-172 sub calculate { Link Here
157
157
158
    # check parameters
158
    # check parameters
159
    my @valid_names = qw(categorycode zipcode branchcode sex sort1 sort2);
159
    my @valid_names = qw(categorycode zipcode branchcode sex sort1 sort2);
160
    my @attribute_types = C4::Members::AttributeTypes::GetAttributeTypes;
161
    if ($line =~ /^patron_attr\.(.*)/) {
160
    if ($line =~ /^patron_attr\.(.*)/) {
162
        my $attribute_type = $1;
161
        my $attribute_type = $1;
163
        return unless (grep {$attribute_type eq $_->{code}} @attribute_types);
162
        return unless Koha::Patron::Attribute::Types->find($attribute_type);
164
    } else {
163
    } else {
165
        return unless (grep { $_ eq $line } @valid_names);
164
        return unless (grep { $_ eq $line } @valid_names);
166
    }
165
    }
167
    if ($column =~ /^patron_attr\.(.*)/) {
166
    if ($column =~ /^patron_attr\.(.*)/) {
168
        my $attribute_type = $1;
167
        my $attribute_type = $1;
169
        return unless (grep {$attribute_type eq $_->{code}} @attribute_types);
168
        return unless Koha::Patron::Attribute::Types->find($attribute_type);
170
    } else {
169
    } else {
171
        return unless (grep { $_ eq $column } @valid_names);
170
        return unless (grep { $_ eq $column } @valid_names);
172
    }
171
    }
Lines 496-506 sub parse_extended_patron_attributes { Link Here
496
sub patron_attributes_form {
495
sub patron_attributes_form {
497
    my $template = shift;
496
    my $template = shift;
498
497
499
    my @types = C4::Members::AttributeTypes::GetAttributeTypes();
498
    my $attribute_types = Koha::Patron::Attribute::Types->filter_by_branch_limitations;
500
499
501
    my %items_by_class;
500
    my %items_by_class;
502
    foreach my $type (@types) {
501
    while ( my $attr_type = $attribute_types->next ) {
503
        my $attr_type = C4::Members::AttributeTypes->fetch($type->{code});
502
        # TODO The following can be simplified easily
504
        my $entry = {
503
        my $entry = {
505
            class             => $attr_type->class(),
504
            class             => $attr_type->class(),
506
            code              => $attr_type->code(),
505
            code              => $attr_type->code(),
(-)a/reports/issues_stats.pl (-3 / +4 lines)
Lines 34-40 use C4::Members; Link Here
34
use Koha::AuthorisedValues;
34
use Koha::AuthorisedValues;
35
use Koha::DateUtils;
35
use Koha::DateUtils;
36
use Koha::ItemTypes;
36
use Koha::ItemTypes;
37
use C4::Members::AttributeTypes;
37
use Koha::Patron::Attribute::Types;
38
38
39
=head1 NAME
39
=head1 NAME
40
40
Lines 166-174 foreach (sort {$ccodes->{$a} cmp $ccodes->{$b}} keys %$ccodes) { Link Here
166
my $CGIextChoice = ( 'CSV' ); # FIXME translation
166
my $CGIextChoice = ( 'CSV' ); # FIXME translation
167
my $CGIsepChoice=GetDelimiterChoices;
167
my $CGIsepChoice=GetDelimiterChoices;
168
168
169
my @attribute_types = C4::Members::AttributeTypes::GetAttributeTypes(1);
169
my $attribute_types = Koha::Patron::Attribute::Types->filter_by_branch_limitations;
170
my %attribute_types_by_class;
170
my %attribute_types_by_class;
171
foreach my $attribute_type (@attribute_types) {
171
while ( my ( $attribute_type ) = $attribute_types->next ) {
172
    $attribute_type = $attribute_type->unblessed;
172
    if ($attribute_type->{authorised_value_category}) {
173
    if ($attribute_type->{authorised_value_category}) {
173
        my $authorised_values = C4::Koha::GetAuthorisedValues(
174
        my $authorised_values = C4::Koha::GetAuthorisedValues(
174
            $attribute_type->{authorised_value_category});
175
            $attribute_type->{authorised_value_category});
(-)a/t/Members_AttributeTypes.t (-1 / +3 lines)
Lines 22-27 use Test::More; Link Here
22
22
23
use Module::Load::Conditional qw/check_install/;
23
use Module::Load::Conditional qw/check_install/;
24
24
25
use Koha::Patron::Attribute::Types;
26
25
BEGIN {
27
BEGIN {
26
    if ( check_install( module => 'Test::DBIx::Class' ) ) {
28
    if ( check_install( module => 'Test::DBIx::Class' ) ) {
27
        plan tests => 8;
29
        plan tests => 8;
Lines 57-63 fixtures_ok [ Link Here
57
my $db = Test::MockModule->new('Koha::Database');
59
my $db = Test::MockModule->new('Koha::Database');
58
$db->mock( _new_schema => sub { return Schema(); } );
60
$db->mock( _new_schema => sub { return Schema(); } );
59
61
60
my @members_attributetypes = C4::Members::AttributeTypes::GetAttributeTypes(undef, 1);
62
my @members_attributetypes = @{Koha::Patron::Attribute::Types->search->unblessed};
61
63
62
is( $members_attributetypes[0]->{'code'}, 'one', 'First code value is one' );
64
is( $members_attributetypes[0]->{'code'}, 'one', 'First code value is one' );
63
65
(-)a/t/db_dependent/Koha/Patron/Attribute/Types.t (+2 lines)
Lines 329-334 subtest 'search_with_library_limits() tests' => sub { Link Here
329
        4, '4 attribute types are available with no library passed'
329
        4, '4 attribute types are available with no library passed'
330
    );
330
    );
331
331
332
    # TODO test if filter_by_branch_limitations restriced on logged-in-user's branch
333
332
    $schema->storage->txn_rollback;
334
    $schema->storage->txn_rollback;
333
};
335
};
334
336
(-)a/tools/import_borrowers.pl (-3 / +4 lines)
Lines 44-49 use Koha::DateUtils; Link Here
44
use Koha::Token;
44
use Koha::Token;
45
use Koha::Libraries;
45
use Koha::Libraries;
46
use Koha::Patron::Categories;
46
use Koha::Patron::Categories;
47
use Koha::Patron::Attribute::Types;
47
use Koha::List::Patron;
48
use Koha::List::Patron;
48
49
49
use Koha::Patrons::Import;
50
use Koha::Patrons::Import;
Lines 167-175 if ( $uploadborrowers && length($uploadborrowers) > 0 ) { Link Here
167
else {
168
else {
168
    if ($extended) {
169
    if ($extended) {
169
        my @matchpoints = ();
170
        my @matchpoints = ();
170
        my @attr_types = C4::Members::AttributeTypes::GetAttributeTypes( undef, 1 );
171
        my $attribute_types = Koha::Patron::Attribute::Types->search;
171
        foreach my $type (@attr_types) {
172
172
            my $attr_type = C4::Members::AttributeTypes->fetch( $type->{code} );
173
        while ( my $attr_type = $attribute_types->next ) {
173
            if ( $attr_type->unique_id() ) {
174
            if ( $attr_type->unique_id() ) {
174
                push @matchpoints,
175
                push @matchpoints,
175
                  { code => "patron_attribute_" . $attr_type->code(), description => $attr_type->description() };
176
                  { code => "patron_attribute_" . $attr_type->code(), description => $attr_type->description() };
(-)a/tools/modborrowers.pl (-12 / +9 lines)
Lines 31-37 use C4::Auth; Link Here
31
use C4::Koha;
31
use C4::Koha;
32
use C4::Members;
32
use C4::Members;
33
use C4::Members::Attributes;
33
use C4::Members::Attributes;
34
use C4::Members::AttributeTypes qw/GetAttributeTypes_hashref/;
35
use C4::Output;
34
use C4::Output;
36
use List::MoreUtils qw /any uniq/;
35
use List::MoreUtils qw /any uniq/;
37
use Koha::DateUtils qw( dt_from_string );
36
use Koha::DateUtils qw( dt_from_string );
Lines 115-145 if ( $op eq 'show' ) { Link Here
115
    # Construct the patron attributes list
114
    # Construct the patron attributes list
116
    my @patron_attributes_values;
115
    my @patron_attributes_values;
117
    my @patron_attributes_codes;
116
    my @patron_attributes_codes;
118
    my $patron_attribute_types = C4::Members::AttributeTypes::GetAttributeTypes_hashref('all');
117
    my $patron_attribute_types = Koha::Patron::Attribute::Types->filter_by_branch_limitations;
119
    my @patron_categories = Koha::Patron::Categories->search_limited({}, {order_by => ['description']});
118
    my @patron_categories = Koha::Patron::Categories->search_limited({}, {order_by => ['description']});
120
    for ( values %$patron_attribute_types ) {
119
    while ( my $attr_type = $patron_attribute_types->next ) {
121
        my $attr_type = C4::Members::AttributeTypes->fetch( $_->{code} );
122
        # TODO Repeatable attributes are not correctly managed and can cause data lost.
120
        # TODO Repeatable attributes are not correctly managed and can cause data lost.
123
        # This should be implemented.
121
        # This should be implemented.
124
        next if $attr_type->{repeatable};
122
        next if $attr_type->repeatable;
125
        next if $attr_type->{unique_id}; # Don't display patron attributes that must be unqiue
123
        next if $attr_type->unique_id; # Don't display patron attributes that must be unqiue
126
        my $options = $attr_type->authorised_value_category
124
        my $options = $attr_type->authorised_value_category
127
            ? GetAuthorisedValues( $attr_type->authorised_value_category )
125
            ? GetAuthorisedValues( $attr_type->authorised_value_category )
128
            : undef;
126
            : undef;
129
        push @patron_attributes_values,
127
        push @patron_attributes_values,
130
            {
128
            {
131
                attribute_code => $_->{code},
129
                attribute_code => $attr_type->code,
132
                options        => $options,
130
                options        => $options,
133
            };
131
            };
134
132
135
        my $category_code = $_->{category_code};
133
        my $category_code = $attr_type->category_code;
136
        my ( $category_lib ) = map {
134
        my ( $category_lib ) = map {
137
            ( defined $category_code and $_->categorycode eq $category_code ) ? $_->description : ()
135
            ( defined $category_code and $attr_type->categorycode eq $category_code ) ? $attr_type->description : ()
138
        } @patron_categories;
136
        } @patron_categories;
139
        push @patron_attributes_codes,
137
        push @patron_attributes_codes,
140
            {
138
            {
141
                attribute_code => $_->{code},
139
                attribute_code => $attr_type->code,
142
                attribute_lib  => $_->{description},
140
                attribute_lib  => $attr_type->description,
143
                category_lib   => $category_lib,
141
                category_lib   => $category_lib,
144
                type           => $attr_type->authorised_value_category ? 'select' : 'text',
142
                type           => $attr_type->authorised_value_category ? 'select' : 'text',
145
            };
143
            };
146
- 

Return to bug 20443