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>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
c04ac1c541
commit
806ac743f0
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ sub _list {
|
|||
package => 'erm_packages',
|
||||
order => 'aqorders',
|
||||
vendor => 'aqbooksellers:vendor',
|
||||
title => 'erm_titles'
|
||||
};
|
||||
|
||||
my @tables;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
- order
|
||||
- subscription
|
||||
- vendor
|
||||
- title
|
||||
- $ref: "../swagger.yaml#/parameters/match"
|
||||
- $ref: "../swagger.yaml#/parameters/order_by"
|
||||
- $ref: "../swagger.yaml#/parameters/page"
|
||||
|
|
|
|||
|
|
@ -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 %]
|
||||
|
|
|
|||
|
|
@ -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 =>
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ export default {
|
|||
props,
|
||||
additionalToolbarButtons,
|
||||
moduleStore: "ERMStore",
|
||||
extendedAttributesResourceType: "title",
|
||||
resourceAttrs: [
|
||||
{
|
||||
name: "publication_title",
|
||||
|
|
@ -443,7 +444,7 @@ export default {
|
|||
const tableOptions = {
|
||||
url: baseResource.getResourceTableUrl(),
|
||||
options: {
|
||||
embed: "resources.package",
|
||||
embed: "resources.package,extended_attributes,+strings",
|
||||
searchCols: [
|
||||
{ search: defaults.publication_title },
|
||||
null,
|
||||
|
|
@ -491,6 +492,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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue