|
Lines 20-27
package Koha::Patron;
Link Here
|
| 20 |
|
20 |
|
| 21 |
use Modern::Perl; |
21 |
use Modern::Perl; |
| 22 |
|
22 |
|
|
|
23 |
use JSON qw( encode_json decode_json ); |
| 23 |
use List::MoreUtils qw( any none uniq notall zip6); |
24 |
use List::MoreUtils qw( any none uniq notall zip6); |
| 24 |
use Scalar::Util qw( blessed looks_like_number ); |
25 |
use Scalar::Util qw( blessed looks_like_number ); |
|
|
26 |
use Struct::Diff qw( diff ); |
| 25 |
use Unicode::Normalize qw( NFKD ); |
27 |
use Unicode::Normalize qw( NFKD ); |
| 26 |
use Try::Tiny; |
28 |
use Try::Tiny; |
| 27 |
use DateTime (); |
29 |
use DateTime (); |
|
Lines 32-37
use C4::Letters qw( GetPreparedLetter EnqueueLetter SendQueuedMessages );
Link Here
|
| 32 |
use C4::Log qw( logaction ); |
34 |
use C4::Log qw( logaction ); |
| 33 |
use C4::Scrubber; |
35 |
use C4::Scrubber; |
| 34 |
use Koha::Account; |
36 |
use Koha::Account; |
|
|
37 |
use Koha::ActionLogs; |
| 35 |
use Koha::ArticleRequests; |
38 |
use Koha::ArticleRequests; |
| 36 |
use Koha::AuthUtils; |
39 |
use Koha::AuthUtils; |
| 37 |
use Koha::Caches; |
40 |
use Koha::Caches; |
|
Lines 336-342
sub store {
Link Here
|
| 336 |
|
339 |
|
| 337 |
if ( C4::Context->preference("BorrowersLog") ) { |
340 |
if ( C4::Context->preference("BorrowersLog") ) { |
| 338 |
my $patron_data = $self->_unblessed_for_log; |
341 |
my $patron_data = $self->_unblessed_for_log; |
| 339 |
logaction( "MEMBERS", "CREATE", $self->borrowernumber, $patron_data, undef, $patron_data ); |
342 |
my $create_log = |
|
|
343 |
logaction( "MEMBERS", "CREATE", $self->borrowernumber, $patron_data, undef, $patron_data ); |
| 344 |
$self->{_patron_log_id} = $create_log->action_id; |
| 340 |
} |
345 |
} |
| 341 |
} else { #ModMember |
346 |
} else { #ModMember |
| 342 |
|
347 |
|
|
Lines 393-400
sub store {
Link Here
|
| 393 |
my %log_from = map { $_ => $from_storage->{$_} } keys %{$changed}; |
398 |
my %log_from = map { $_ => $from_storage->{$_} } keys %{$changed}; |
| 394 |
my %log_to = map { $_ => $from_object->{$_} } keys %{$changed}; |
399 |
my %log_to = map { $_ => $from_object->{$_} } keys %{$changed}; |
| 395 |
|
400 |
|
| 396 |
logaction( "MEMBERS", "MODIFY", $self->borrowernumber, \%log_to, undef, \%log_from ) |
401 |
if ( C4::Context->preference("BorrowersLog") ) { |
| 397 |
if C4::Context->preference("BorrowersLog"); |
402 |
my $modify_log = |
|
|
403 |
logaction( "MEMBERS", "MODIFY", $self->borrowernumber, \%log_to, undef, \%log_from ); |
| 404 |
$self->{_patron_log_id} = $modify_log->action_id; |
| 405 |
} |
| 398 |
|
406 |
|
| 399 |
logaction( |
407 |
logaction( |
| 400 |
"MEMBERS", |
408 |
"MEMBERS", |
|
Lines 450-456
sub delete {
Link Here
|
| 450 |
# for patron selfreg |
458 |
# for patron selfreg |
| 451 |
$_->delete for Koha::Patron::Modifications->search( { borrowernumber => $self->borrowernumber } )->as_list; |
459 |
$_->delete for Koha::Patron::Modifications->search( { borrowernumber => $self->borrowernumber } )->as_list; |
| 452 |
|
460 |
|
| 453 |
my $patron_data = C4::Context->preference("BorrowersLog") ? $self->_unblessed_for_log : undef; |
461 |
my $patron_data; |
|
|
462 |
if ( C4::Context->preference("BorrowersLog") ) { |
| 463 |
$patron_data = $self->_unblessed_for_log; |
| 464 |
for my $attr ( $self->extended_attributes->as_list ) { |
| 465 |
my $key = "attribute." . $attr->code; |
| 466 |
if ( $attr->type->repeatable ) { |
| 467 |
$patron_data->{$key} //= []; |
| 468 |
push @{ $patron_data->{$key} }, $attr->attribute; |
| 469 |
} else { |
| 470 |
$patron_data->{$key} = $attr->attribute; |
| 471 |
} |
| 472 |
} |
| 473 |
} |
| 454 |
|
474 |
|
| 455 |
$self->SUPER::delete; |
475 |
$self->SUPER::delete; |
| 456 |
|
476 |
|
|
Lines 2681-2687
sub extended_attributes {
Link Here
|
| 2681 |
if ( %{$all_changes} ) { |
2701 |
if ( %{$all_changes} ) { |
| 2682 |
my %log_from = map { $_ => $all_changes->{$_}->{before} } keys %{$all_changes}; |
2702 |
my %log_from = map { $_ => $all_changes->{$_}->{before} } keys %{$all_changes}; |
| 2683 |
my %log_to = map { $_ => $all_changes->{$_}->{after} } keys %{$all_changes}; |
2703 |
my %log_to = map { $_ => $all_changes->{$_}->{after} } keys %{$all_changes}; |
| 2684 |
logaction( "MEMBERS", "MODIFY", $self->borrowernumber, \%log_to, undef, \%log_from ); |
2704 |
if ( my $log_id = delete $self->{_patron_log_id} ) { |
|
|
2705 |
$self->_merge_attribute_log( $log_id, \%log_to, \%log_from ); |
| 2706 |
} else { |
| 2707 |
logaction( "MEMBERS", "MODIFY", $self->borrowernumber, \%log_to, undef, \%log_from ); |
| 2708 |
} |
| 2709 |
} else { |
| 2710 |
delete $self->{_patron_log_id}; |
| 2685 |
} |
2711 |
} |
| 2686 |
} |
2712 |
} |
| 2687 |
); |
2713 |
); |
|
Lines 3652-3657
sub _type {
Link Here
|
| 3652 |
return 'Borrower'; |
3678 |
return 'Borrower'; |
| 3653 |
} |
3679 |
} |
| 3654 |
|
3680 |
|
|
|
3681 |
=head3 _merge_attribute_log |
| 3682 |
|
| 3683 |
Merges extended attribute changes into an existing action log entry (identified |
| 3684 |
by action_id), combining field and attribute changes into a single log entry. |
| 3685 |
Used to unify CREATE/MODIFY log entries with subsequent attribute changes. |
| 3686 |
|
| 3687 |
=cut |
| 3688 |
|
| 3689 |
sub _merge_attribute_log { |
| 3690 |
my ( $self, $log_id, $log_to, $log_from ) = @_; |
| 3691 |
|
| 3692 |
my $log = Koha::ActionLogs->find($log_id); |
| 3693 |
return unless $log; |
| 3694 |
|
| 3695 |
my $info = {}; |
| 3696 |
eval { $info = decode_json( $log->info ) } if $log->info; |
| 3697 |
%{$info} = ( %{$info}, %{$log_to} ); |
| 3698 |
|
| 3699 |
my $existing_diff = {}; |
| 3700 |
eval { $existing_diff = decode_json( $log->diff ) } if $log->diff; |
| 3701 |
my $attr_diff = diff( $log_from, $log_to, noU => 1 ); |
| 3702 |
if ( $attr_diff->{D} ) { |
| 3703 |
$existing_diff->{D} //= {}; |
| 3704 |
%{ $existing_diff->{D} } = ( %{ $existing_diff->{D} }, %{ $attr_diff->{D} } ); |
| 3705 |
} |
| 3706 |
|
| 3707 |
$log->set( |
| 3708 |
{ |
| 3709 |
info => encode_json($info), |
| 3710 |
diff => encode_json($existing_diff), |
| 3711 |
} |
| 3712 |
)->store; |
| 3713 |
} |
| 3714 |
|
| 3655 |
=head3 _unblessed_for_log |
3715 |
=head3 _unblessed_for_log |
| 3656 |
|
3716 |
|
| 3657 |
Returns a plain hashref of patron column values safe for JSON serialisation. |
3717 |
Returns a plain hashref of patron column values safe for JSON serialisation. |