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 |
- |
|
|