Bugzilla – Attachment 189019 Details for
Bug 40192
Add additional fields to ERM titles
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 40192: Add additional fields support to ERM titles
Bug-40192-Add-additional-fields-support-to-ERM-tit.patch (text/plain), 13.06 KB, created by
Jonathan Druart
on 2025-11-04 15:21:00 UTC
(
hide
)
Description:
Bug 40192: Add additional fields support to ERM titles
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2025-11-04 15:21:00 UTC
Size:
13.06 KB
patch
obsolete
>From 9481dcd3106e4c1c0cf2e3d4f6da34f0736787de Mon Sep 17 00:00:00 2001 >From: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk> >Date: Tue, 21 Oct 2025 10:56:32 +0100 >Subject: [PATCH] Bug 40192: Add additional fields support to ERM titles > >This patch extends the additional fields framework to ERM e-holdings >titles, allowing libraries to configure custom metadata fields for >managing electronic resources. > >Implementation details: >- Extended Koha::ERM::EHoldings::Title and ::Titles with > AdditionalFields mixin for object-level support >- Added 'erm_titles' table mapping to AdditionalField.pm for API > serialization >- Updated OpenAPI schema definitions to include extended_attributes > in erm_eholdings_title.yaml and expose extended_attribute_types > endpoint >- Enhanced REST API controller to handle additional fields in title > creation/updates >- Updated admin interface to allow configuring additional fields for > the 'title' table name >- Modified Vue.js EHoldingsLocalTitleResource component to display > and manage custom fields > >This enables institutions to track custom metadata (e.g., license >details, administrative notes, local identifiers) alongside standard >ERM title information. > >Test plan: >1. Configure additional fields: > - Go to Administration > Additional fields > - Click "New field" and select table name "title" > - Create a text field: Name="License notes", Searchable=Yes > - Create an authorized value field: Name="Access level", > AV category=LOC (or any available category) > - Save both fields > >2. Test with local ERM titles: > - Navigate to E-resource management > Local titles > - Create a new local title or edit an existing one > - Verify the "Additional fields" section appears with your > configured fields > - Fill in "License notes" with test text > - Select a value for "Access level" > - Save the title > >3. Verify persistence: > - Reopen the title you just edited > - Confirm both additional field values are displayed correctly > - Edit one field value and save > - Confirm the update persists > >Signed-off-by: Michaela <michaela.sieber@kit.edu> >Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk> >--- > Koha/AdditionalField.pm | 1 + > Koha/ERM/EHoldings/Title.pm | 2 +- > Koha/ERM/EHoldings/Titles.pm | 2 +- > Koha/REST/V1/ERM/EHoldings/Titles/Local.pm | 9 ++++++ > Koha/REST/V1/ExtendedAttributeTypes.pm | 1 + > Koha/Schema/Result/ErmEholdingsTitle.pm | 32 +++++++++++++++++++ > .../definitions/erm_eholdings_title.yaml | 10 ++++++ > .../swagger/paths/erm_eholdings_titles.yaml | 4 +++ > .../paths/extended_attribute_types.yaml | 1 + > .../en/modules/admin/additional-fields.tt | 3 +- > .../prog/js/fetch/erm-api-client.js | 3 +- > .../ERM/EHoldingsLocalTitleResource.vue | 4 ++- > 12 files changed, 67 insertions(+), 5 deletions(-) > >diff --git a/Koha/AdditionalField.pm b/Koha/AdditionalField.pm >index ead7d3e4fb5..bf5e5c08146 100644 >--- a/Koha/AdditionalField.pm >+++ b/Koha/AdditionalField.pm >@@ -64,6 +64,7 @@ sub to_api { > 'erm_packages' => 'package', > 'aqorders' => 'order', > 'aqbooksellers:vendor' => 'vendor', >+ 'erm_titles' => 'title' > }; > > my $json = $self->SUPER::to_api($params); >diff --git a/Koha/ERM/EHoldings/Title.pm b/Koha/ERM/EHoldings/Title.pm >index 6192b75588f..3a07b41460a 100644 >--- a/Koha/ERM/EHoldings/Title.pm >+++ b/Koha/ERM/EHoldings/Title.pm >@@ -22,7 +22,7 @@ use MIME::Base64 qw( decode_base64 ); > > use Koha::Database; > >-use base qw(Koha::Object); >+use base qw(Koha::Object::Mixin::AdditionalFields Koha::Object); > > use C4::Biblio qw( AddBiblio TransformKohaToMarc GetMarcFromKohaField ); > >diff --git a/Koha/ERM/EHoldings/Titles.pm b/Koha/ERM/EHoldings/Titles.pm >index 5b914345bd1..cd3390f9e8a 100644 >--- a/Koha/ERM/EHoldings/Titles.pm >+++ b/Koha/ERM/EHoldings/Titles.pm >@@ -21,7 +21,7 @@ use Koha::Database; > > use Koha::ERM::EHoldings::Title; > >-use base qw(Koha::Objects); >+use base qw(Koha::Objects::Mixin::AdditionalFields Koha::Objects); > > =head1 NAME > >diff --git a/Koha/REST/V1/ERM/EHoldings/Titles/Local.pm b/Koha/REST/V1/ERM/EHoldings/Titles/Local.pm >index 10e556980b1..9041cc43a77 100644 >--- a/Koha/REST/V1/ERM/EHoldings/Titles/Local.pm >+++ b/Koha/REST/V1/ERM/EHoldings/Titles/Local.pm >@@ -90,12 +90,17 @@ sub add { > > my $resources = delete $body->{resources} // []; > my $create_linked_biblio = delete $body->{create_linked_biblio} // 0; >+ my $extended_attributes = delete $body->{extended_attributes} // []; > > my $title = Koha::ERM::EHoldings::Title->new_from_api($body) > ->store( { create_linked_biblio => $create_linked_biblio } ); > > $title->resources($resources); > >+ my @extended_attributes = >+ map { { 'id' => $_->{field_id}, 'value' => $_->{value} } } @{$extended_attributes}; >+ $title->extended_attributes( \@extended_attributes ); >+ > $c->res->headers->location( $c->req->url->to_string . '/' . $title->title_id ); > return $c->render( > status => 201, >@@ -152,10 +157,14 @@ sub update { > > my $resources = delete $body->{resources} // []; > my $create_linked_biblio = delete $body->{create_linked_biblio} // 0; >+ my $extended_attributes = delete $body->{extended_attributes} // []; > > $title->set_from_api($body)->store( { create_linked_biblio => $create_linked_biblio } ); > > $title->resources($resources); >+ my @extended_attributes = >+ map { { 'id' => $_->{field_id}, 'value' => $_->{value} } } @{$extended_attributes}; >+ $title->extended_attributes( \@extended_attributes ); > > return $c->render( > status => 200, >diff --git a/Koha/REST/V1/ExtendedAttributeTypes.pm b/Koha/REST/V1/ExtendedAttributeTypes.pm >index e46395c577b..6505996408d 100644 >--- a/Koha/REST/V1/ExtendedAttributeTypes.pm >+++ b/Koha/REST/V1/ExtendedAttributeTypes.pm >@@ -53,6 +53,7 @@ sub _list { > package => 'erm_packages', > order => 'aqorders', > vendor => 'aqbooksellers:vendor', >+ title => 'erm_titles' > }; > > my @tables; >diff --git a/Koha/Schema/Result/ErmEholdingsTitle.pm b/Koha/Schema/Result/ErmEholdingsTitle.pm >index d8b2ef732b1..a9049e616a7 100644 >--- a/Koha/Schema/Result/ErmEholdingsTitle.pm >+++ b/Koha/Schema/Result/ErmEholdingsTitle.pm >@@ -297,6 +297,38 @@ __PACKAGE__->has_many( > # Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-09-13 11:06:45 > # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SOFpN45kBTi/qvW5OBnYDA > >+__PACKAGE__->has_many( >+ "additional_field_values", >+ "Koha::Schema::Result::AdditionalFieldValue", >+ sub { >+ my ($args) = @_; >+ >+ return { >+ "$args->{foreign_alias}.record_id" => { -ident => "$args->{self_alias}.title_id" }, >+ >+ "$args->{foreign_alias}.field_id" => >+ { -in => \'(SELECT id FROM additional_fields WHERE tablename="erm_titles")' }, >+ }; >+ }, >+ { cascade_copy => 0, cascade_delete => 0 }, >+); >+ >+__PACKAGE__->has_many( >+ "extended_attributes", >+ "Koha::Schema::Result::AdditionalFieldValue", >+ sub { >+ my ($args) = @_; >+ >+ return { >+ "$args->{foreign_alias}.record_id" => { -ident => "$args->{self_alias}.title_id" }, >+ >+ "$args->{foreign_alias}.field_id" => >+ { -in => \'(SELECT id FROM additional_fields WHERE tablename="erm_titles")' }, >+ }; >+ }, >+ { cascade_copy => 0, cascade_delete => 0 }, >+); >+ > =head2 koha_objects_class > > Missing POD for koha_objects_class. >diff --git a/api/v1/swagger/definitions/erm_eholdings_title.yaml b/api/v1/swagger/definitions/erm_eholdings_title.yaml >index 6bbadd61e4b..c1eae480a32 100644 >--- a/api/v1/swagger/definitions/erm_eholdings_title.yaml >+++ b/api/v1/swagger/definitions/erm_eholdings_title.yaml >@@ -173,6 +173,16 @@ properties: > type: > - boolean > - "null" >+ extended_attributes: >+ description: Related additional field values >+ type: >+ - array >+ items: >+ $ref: extended_attribute_value.yaml >+ _strings: >+ type: >+ - object >+ - "null" > > additionalProperties: false > required: >diff --git a/api/v1/swagger/paths/erm_eholdings_titles.yaml b/api/v1/swagger/paths/erm_eholdings_titles.yaml >index 87e037b5b3a..f68eaeb8539 100644 >--- a/api/v1/swagger/paths/erm_eholdings_titles.yaml >+++ b/api/v1/swagger/paths/erm_eholdings_titles.yaml >@@ -153,6 +153,8 @@ > type: string > enum: > - resources.package >+ - extended_attributes >+ - +strings > collectionFormat: csv > - $ref: "../swagger.yaml#/parameters/match" > - $ref: "../swagger.yaml#/parameters/order_by" >@@ -278,6 +280,8 @@ > enum: > - resources > - resources.package >+ - extended_attributes >+ - +strings > collectionFormat: csv > responses: > 200: >diff --git a/api/v1/swagger/paths/extended_attribute_types.yaml b/api/v1/swagger/paths/extended_attribute_types.yaml >index 4b7b56d71b7..675a80a2506 100644 >--- a/api/v1/swagger/paths/extended_attribute_types.yaml >+++ b/api/v1/swagger/paths/extended_attribute_types.yaml >@@ -24,6 +24,7 @@ > - order > - subscription > - vendor >+ - title > - $ref: "../swagger.yaml#/parameters/match" > - $ref: "../swagger.yaml#/parameters/order_by" > - $ref: "../swagger.yaml#/parameters/page" >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt >index 78ddf642e7e..3dbb35ca67c 100755 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/additional-fields.tt >@@ -30,7 +30,7 @@ > </head> > > [% marcfield_tables = ['subscription', 'aqorders'] %] >-[% searchable_tables = ['subscription', 'aqbasket', 'aqinvoices', 'erm_licenses', 'erm_agreements', 'erm_packages', 'aqbooksellers:vendor'] %] >+[% searchable_tables = ['subscription', 'aqbasket', 'aqinvoices', 'erm_licenses', 'erm_agreements', 'erm_packages', 'aqbooksellers:vendor', 'erm_titles'] %] > [% show_marcfield = marcfield_tables.grep('^' _ tablename _ '$').size ? 1 : 0 %] > [% show_searchable = searchable_tables.grep('^' _ tablename _ '$').size ? 1 : 0 %] > >@@ -146,6 +146,7 @@ > [% WRAPPER table_option value="erm_agreements" %]Agreements[% END %] > [% WRAPPER table_option value="erm_licenses" %]Licenses[% END %] > [% WRAPPER table_option value="erm_packages" %]Packages[% END %] >+ [% WRAPPER table_option value="erm_titles" %]Titles[% END %] > </ul> > [% END %] > [% IF CAN_user_updatecharges_remaining_permissions || CAN_user_parameters_manage_accounts %] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/fetch/erm-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/fetch/erm-api-client.js >index ba64f3a88cf..68091565a4e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/fetch/erm-api-client.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/fetch/erm-api-client.js >@@ -155,7 +155,8 @@ export class ERMAPIClient { > this.httpClient.get({ > endpoint: "eholdings/local/titles/" + id, > headers: { >- "x-koha-embed": "resources,resources.package", >+ "x-koha-embed": >+ "resources,resources.package,extended_attributes,+strings", > }, > }), > delete: id => >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsLocalTitleResource.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsLocalTitleResource.vue >index c81a0fb31d4..8a1cf7d0557 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsLocalTitleResource.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/ERM/EHoldingsLocalTitleResource.vue >@@ -68,6 +68,7 @@ export default { > props, > additionalToolbarButtons, > moduleStore: "ERMStore", >+ extendedAttributesResourceType: "title", > resourceAttrs: [ > { > name: "publication_title", >@@ -440,7 +441,7 @@ export default { > const tableOptions = { > url: baseResource.getResourceTableUrl(), > options: { >- embed: "resources.package", >+ embed: "resources.package,extended_attributes,+strings", > searchCols: [ > { search: defaults.publication_title }, > null, >@@ -488,6 +489,7 @@ export default { > let title_id = title.title_id; > delete title.title_id; > delete title.biblio_id; >+ delete title._strings; > > // Cannot use the map/keepAttrs because of the reserved keyword 'package' > title.resources.forEach(function (e) { >-- >2.34.1
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 40192
:
188211
|
188371
|
188374
|
188378
|
188777
| 189019 |
189020