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