Bugzilla – Attachment 193836 Details for
Bug 27364
Making previous patron cardnumbers searchable
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 27364: Add historic_cardnumbers to Patron object & API
bacf6fb.patch (text/plain), 8.71 KB, created by
Jake Deery
on 2026-02-25 09:29:21 UTC
(
hide
)
Description:
Bug 27364: Add historic_cardnumbers to Patron object & API
Filename:
MIME Type:
Creator:
Jake Deery
Created:
2026-02-25 09:29:21 UTC
Size:
8.71 KB
patch
obsolete
>From bacf6fb395b6f508bf6c60a7e84869d7ce923ef6 Mon Sep 17 00:00:00 2001 >From: Jake Deery <jake.deery@openfifth.co.uk> >Date: Mon, 23 Feb 2026 17:25:22 +0000 >Subject: [PATCH] Bug 27364: Add historic_cardnumbers to Patron object & API > >This patch adds an historic_cardnumbers field to the patron object, staff client, and API call (which will return an array of objects containing information about the cardnumber and when it was changed). > >TO TEST: >== APPLY PATCH == >a) Ensure 'CardnumberLog' is on in the sysprefs >b) Change the koha user's cardnumber from 42 to 67 >c) Reverse step b) >d) Go to the koha user's details page > *) note how there is a historic cardnumbers box > *) note how each change is marked, next to the date and time > performed > *) note how the time is accurate to minutes >e) Go to /api/v1/patrons/51 > *) notice how the historic_cardnumbers array is populated with two > objects > *) each object is per cardnumber change > *) each object contains the new and old cardnumber, as well as the > timestamp of the transaction >== RESET_ALL == >f) repeat steps d-e > *) notice how the historic cardnumbers section is missing if no > cardnumber change has occured, on the patron details page > *) notice how the historic_cardnumbers array is empty in the api > call, if no cardnumber change has occured >== SIGN OFF == >--- > Koha/Patron.pm | 45 ++++++++++++++++++- > .../definitions/historic_cardnumbers.yaml | 18 ++++++++ > api/v1/swagger/definitions/patron.yaml | 7 +++ > .../prog/en/modules/members/moremember.tt | 19 ++++++++ > members/moremember.pl | 6 +++ > t/db_dependent/Koha/Patrons.t | 17 ++++++- > 6 files changed, 110 insertions(+), 2 deletions(-) > create mode 100644 api/v1/swagger/definitions/historic_cardnumbers.yaml > >diff --git a/Koha/Patron.pm b/Koha/Patron.pm >index c0ef6e292c5..2bc1bff87a3 100644 >--- a/Koha/Patron.pm >+++ b/Koha/Patron.pm >@@ -21,7 +21,7 @@ package Koha::Patron; > use Modern::Perl; > > use List::MoreUtils qw( any none uniq notall zip6); >-use JSON qw( to_json ); >+use JSON qw( from_json to_json ); > use Scalar::Util qw(looks_like_number); > use Unicode::Normalize qw( NFKD ); > use Try::Tiny; >@@ -33,6 +33,7 @@ use C4::Letters qw( GetPreparedLetter EnqueueLetter SendQueuedMessages ); > use C4::Log qw( logaction ); > use C4::Scrubber; > use Koha::Account; >+use Koha::ActionLogs; > use Koha::ArticleRequests; > use Koha::AuthUtils; > use Koha::Caches; >@@ -639,6 +640,46 @@ sub relationships_debt { > return $non_issues_charges; > } > >+=head3 historic_cardnumbers >+ >+Returns a list of historic cardnumbers and their change date, or undef >+ >+=cut >+ >+sub historic_cardnumbers { >+ my ($self) = @_; >+ >+ my $logentries = Koha::ActionLogs->search( >+ { >+ module => 'MEMBERS', >+ action => 'MODIFY_CARDNUMBER', >+ object => $self->borrowernumber, >+ }, >+ { order_by => { -desc => 'timestamp' } } >+ )->unblessed or return; >+ >+ my @cardnumbers; >+ for my $logentry ( @{$logentries} ) { >+ my $info = from_json( $logentry->{info} ); >+ my $timestamp = $logentry->{timestamp}; >+ >+ next >+ unless $info->{before} >+ and $info->{after} >+ and $timestamp; >+ >+ my $object = { >+ previous_cardnumber => $info->{before}, >+ new_cardnumber => $info->{after}, >+ timestamp => $timestamp, >+ }; >+ >+ push @cardnumbers, $object; >+ } >+ >+ return \@cardnumbers; >+} >+ > =head3 housebound_profile > > Returns the HouseboundProfile associated with this patron. >@@ -3020,6 +3061,8 @@ sub to_api { > ? Mojo::JSON->true > : Mojo::JSON->false; > >+ $json_patron->{historic_cardnumbers} = $self->historic_cardnumbers; >+ > return $json_patron; > } > >diff --git a/api/v1/swagger/definitions/historic_cardnumbers.yaml b/api/v1/swagger/definitions/historic_cardnumbers.yaml >new file mode 100644 >index 00000000000..1803a3c1a3b >--- /dev/null >+++ b/api/v1/swagger/definitions/historic_cardnumbers.yaml >@@ -0,0 +1,18 @@ >+--- >+type: object >+properties: >+ previous_cardnumber: >+ description: The previous cardnumber of this patron >+ type: string >+ new_cardnumber: >+ description: The new cardnumber of this patron >+ type: string >+ timestamp: >+ description: The date and time of the cardnumber change >+ type: >+ - string >+additionalProperties: false >+required: >+ - previous_cardnumber >+ - new_cardnumber >+ - timestamp >diff --git a/api/v1/swagger/definitions/patron.yaml b/api/v1/swagger/definitions/patron.yaml >index afb252e1f17..b5873ad0445 100644 >--- a/api/v1/swagger/definitions/patron.yaml >+++ b/api/v1/swagger/definitions/patron.yaml >@@ -408,6 +408,13 @@ properties: > - "null" > description: patron's primary contact method > maxLength: 45 >+ historic_cardnumbers: >+ type: >+ - array >+ - "null" >+ description: patron's historic cardnumbers >+ items: >+ $ref: "historic_cardnumbers.yaml" > _strings: > type: > - object >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >index cc59617307f..a9ed815723c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt >@@ -627,6 +627,25 @@ > [%# /div#patron-consents %] > [% END %] > >+ [% IF historic_cardnumbers.size %] >+ <div id="historic-cardnumbers" class="patroninfo-section"> >+ <div class="patroninfo-heading"> >+ <h3>Historic cardnumbers</h3> >+ </div> >+ <div class="rows"> >+ <ol> >+ [% FOREACH historic_cardnumber IN historic_cardnumbers %] >+ <li> >+ <span class="label">[% historic_cardnumber.timestamp | $KohaDates with_hours => 1 %]:</span> >+ [% historic_cardnumber.previous_cardnumber | html %] → [% historic_cardnumber.new_cardnumber | html %] >+ </li> >+ [% END %] >+ </ol> >+ </div> >+ </div> >+ [%# /div#historic-cardnumbers %] >+ [% END %] >+ > <div id="patron-alternate-address" class="patroninfo-section"> > [% IF ( patron.B_phone || patron.B_email || patron.contactnote || patron.B_address || patron.B_address2 || patron.B_city || patron.B_zipcode || patron.B_country ) %] > <div class="patroninfo-heading"> >diff --git a/members/moremember.pl b/members/moremember.pl >index b64a58e3000..efb059d19f3 100755 >--- a/members/moremember.pl >+++ b/members/moremember.pl >@@ -317,6 +317,12 @@ if ( C4::Context->preference('UseRecalls') ) { > ); > } > >+if ( C4::Context->preference('CardnumberLog') ) { >+ $template->param( >+ historic_cardnumbers => $patron->historic_cardnumbers, >+ ); >+} >+ > # Fetch available consent types and patron's consents > my $consent_types = Koha::Patron::Consents->available_types; > if ( keys %$consent_types ) { >diff --git a/t/db_dependent/Koha/Patrons.t b/t/db_dependent/Koha/Patrons.t >index 16ef2b22080..7965fcbd9a7 100755 >--- a/t/db_dependent/Koha/Patrons.t >+++ b/t/db_dependent/Koha/Patrons.t >@@ -2029,7 +2029,7 @@ $retrieved_patron_1->delete; > is( Koha::Patrons->search->count, $nb_of_patrons - 1, 'Delete should have deleted the patron' ); > > subtest 'BorrowersLog and CardnumberLog tests' => sub { >- plan tests => 13; >+ plan tests => 16; > > t::lib::Mocks::mock_preference( 'BorrowersLog', 1 ); > t::lib::Mocks::mock_preference( 'CardnumberLog', 0 ); >@@ -2081,6 +2081,21 @@ subtest 'BorrowersLog and CardnumberLog tests' => sub { > 'With CardnumberLog, one detailed MODIFY_CARDNUMBER action should be logged for the modification.' > ); > >+ ## test for historic_cardnumber accessor >+ my @historic_cardnumbers = @{ $patron->historic_cardnumbers }; >+ is( >+ $historic_cardnumbers[0]->{previous_cardnumber}, 'TESTCARDNUMBER', >+ 'previous_cardnumber in historic_cardnumbers[0] should be TESTCARDNUMBER' >+ ); >+ is( >+ $historic_cardnumbers[0]->{new_cardnumber}, 'TESTCARDNUMBER_1', >+ 'new_cardnumber in historic_cardnumbers[0] should be TESTCARDNUMBER_1' >+ ); >+ is( >+ exists( $historic_cardnumbers[0]->{timestamp} ), 1, >+ 'timestamp in historic_cardnumbers[0] should be set' >+ ); >+ > t::lib::Mocks::mock_preference( 'BorrowersLog', 0 ); > $patron->set( { cardnumber => 'TESTCARDNUMBER' } )->store; > @logs = $schema->resultset('ActionLog') >-- >2.50.1 (Apple Git-155) >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 27364
: 193836