diff --git a/Koha/REST/V1/SIP2/Accounts.pm b/Koha/REST/V1/SIP2/Accounts.pm index e1fa2ce4a2..737788abe6 100644 --- a/Koha/REST/V1/SIP2/Accounts.pm +++ b/Koha/REST/V1/SIP2/Accounts.pm @@ -87,6 +87,7 @@ sub add { my $item_fields = delete $body->{item_fields} // []; my $custom_patron_fields = delete $body->{custom_patron_fields} // []; my $patron_attributes = delete $body->{patron_attributes} // []; + my $sort_bin_mappings = delete $body->{sort_bin_mappings} // []; my $system_preference_overrides = delete $body->{system_preference_overrides} // []; my $account = Koha::SIP2::Account->new_from_api($body)->store; @@ -94,6 +95,7 @@ sub add { $account->item_fields($item_fields); $account->custom_patron_fields($custom_patron_fields); $account->patron_attributes($patron_attributes); + $account->sort_bin_mappings($sort_bin_mappings); $account->system_preference_overrides($system_preference_overrides); $c->res->headers->location( $c->req->url->to_string . '/' . $account->sip_account_id ); @@ -149,6 +151,7 @@ sub update { my $item_fields = delete $body->{item_fields} // []; my $custom_patron_fields = delete $body->{custom_patron_fields} // []; my $patron_attributes = delete $body->{patron_attributes} // []; + my $sort_bin_mappings = delete $body->{sort_bin_mappings} // []; my $system_preference_overrides = delete $body->{system_preference_overrides} // []; $account->set_from_api($body)->store; @@ -156,6 +159,7 @@ sub update { $account->item_fields($item_fields); $account->custom_patron_fields($custom_patron_fields); $account->patron_attributes($patron_attributes); + $account->sort_bin_mappings($sort_bin_mappings); $account->system_preference_overrides($system_preference_overrides); $c->res->headers->location( $c->req->url->to_string . '/' . $account->sip_account_id ); diff --git a/Koha/SIP2/Account.pm b/Koha/SIP2/Account.pm index 02019c3f94..990b087ba6 100644 --- a/Koha/SIP2/Account.pm +++ b/Koha/SIP2/Account.pm @@ -23,6 +23,7 @@ use Koha::SIP2::Account::CustomItemFields; use Koha::SIP2::Account::ItemFields; use Koha::SIP2::Account::CustomPatronFields; use Koha::SIP2::Account::PatronAttributes; +use Koha::SIP2::Account::SortBinMappings; use Koha::SIP2::Account::SystemPreferenceOverrides; use Koha::SIP2::Institution; @@ -104,6 +105,12 @@ sub get_for_config { $unblessed->{syspref_overrides} = \%system_preference_overrides; } + my @sort_bin_mappings = map { $_->get_for_config } @{ $self->sort_bin_mappings->as_list }; + if (@sort_bin_mappings) { + $unblessed->{sort_bin_mapping} = + scalar(@sort_bin_mappings) == 1 ? $sort_bin_mappings[0] : \@sort_bin_mappings; + } + return $unblessed; } @@ -224,6 +231,32 @@ sub patron_attributes { return Koha::SIP2::Account::PatronAttributes->_new_from_dbic($patron_attributes_rs); } +=head3 sort_bin_mappings + +Returns the sort bin mappings for this SIP account + +=cut + +sub sort_bin_mappings { + my ( $self, $sort_bin_mappings ) = @_; + + if ($sort_bin_mappings) { + my $schema = $self->_result->result_source->schema; + $schema->txn_do( + sub { + $self->sort_bin_mappings->delete; + + for my $sort_bin_mapping (@$sort_bin_mappings) { + $self->_result->add_to_sip_account_sort_bin_mappings($sort_bin_mapping); + } + } + ); + } + + my $sort_bin_mappings_rs = $self->_result->sip_account_sort_bin_mappings; + return Koha::SIP2::Account::SortBinMappings->_new_from_dbic($sort_bin_mappings_rs); +} + =head3 system_preference_overrides Returns the system preference overrides for this SIP account diff --git a/Koha/SIP2/Account/SortBinMapping.pm b/Koha/SIP2/Account/SortBinMapping.pm new file mode 100644 index 0000000000..c769dfacb4 --- /dev/null +++ b/Koha/SIP2/Account/SortBinMapping.pm @@ -0,0 +1,58 @@ +package Koha::SIP2::Account::SortBinMapping; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::SIP2::Account::SortBinMapping - Koha SIP2 Account Sort Bin Mapping Object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 get_for_config + +Returns the sort bin mapping hashref as expected by C4/SIP/Sip/Configuration->new; + +=cut + +sub get_for_config { + my ($self) = @_; + + return { + 'mapping' => $self->mapping, + }; +} + +=head2 Internal methods + +=head3 _type + +=cut + +sub _type { + return 'SipAccountSortBinMapping'; +} + +1; diff --git a/Koha/SIP2/Account/SortBinMappings.pm b/Koha/SIP2/Account/SortBinMappings.pm new file mode 100644 index 0000000000..c60d3cd1ff --- /dev/null +++ b/Koha/SIP2/Account/SortBinMappings.pm @@ -0,0 +1,52 @@ +package Koha::SIP2::Account::SortBinMappings; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Koha::Database; + +use Koha::SIP2::Account::SortBinMapping; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::SIP2::Account::SortBinMappings - Koha SIP2 Account Sort Bin Mappings Object set class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'SipAccountSortBinMapping'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::SIP2::Account::SortBinMapping'; +} + +1; diff --git a/Koha/Schema/Result/SipAccount.pm b/Koha/Schema/Result/SipAccount.pm index 24ca89704c..711c01693c 100644 --- a/Koha/Schema/Result/SipAccount.pm +++ b/Koha/Schema/Result/SipAccount.pm @@ -406,6 +406,21 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +=head2 sip_account_sort_bin_mappings + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "sip_account_sort_bin_mappings", + "Koha::Schema::Result::SipAccountSortBinMapping", + { "foreign.sip_account_id" => "self.sip_account_id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + =head2 sip_account_system_preference_overrides Type: has_many @@ -437,8 +452,8 @@ __PACKAGE__->belongs_to( ); -# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-02-05 13:46:36 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:WMlJotQoh47vVKXLPZ93cg +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-02-06 16:48:50 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:HkXHNDQw+5MKHCjxhbCdmA __PACKAGE__->add_columns( diff --git a/Koha/Schema/Result/SipAccountSortBinMapping.pm b/Koha/Schema/Result/SipAccountSortBinMapping.pm new file mode 100644 index 0000000000..41909160cc --- /dev/null +++ b/Koha/Schema/Result/SipAccountSortBinMapping.pm @@ -0,0 +1,113 @@ +use utf8; +package Koha::Schema::Result::SipAccountSortBinMapping; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::SipAccountSortBinMapping + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("sip_account_sort_bin_mappings"); + +=head1 ACCESSORS + +=head2 sip_account_sort_bin_mapping_id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 sip_account_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +Foreign key to sip_accounts.sip_account_id + +=head2 mapping + + data_type: 'varchar' + is_nullable: 0 + size: 255 + +The mapping definition + +=cut + +__PACKAGE__->add_columns( + "sip_account_sort_bin_mapping_id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "sip_account_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "mapping", + { data_type => "varchar", is_nullable => 0, size => 255 }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("sip_account_sort_bin_mapping_id"); + +=head1 UNIQUE CONSTRAINTS + +=head2 C + +=over 4 + +=item * L + +=item * L + +=back + +=cut + +__PACKAGE__->add_unique_constraint( + "sip_account", + ["sip_account_sort_bin_mapping_id", "sip_account_id"], +); + +=head1 RELATIONS + +=head2 sip_account + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "sip_account", + "Koha::Schema::Result::SipAccount", + { sip_account_id => "sip_account_id" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-02-06 16:48:50 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:0qnrb3rQha57wadFOFZo+w + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/api/v1/swagger/definitions/sip2_account.yaml b/api/v1/swagger/definitions/sip2_account.yaml index 90cf037c22..0a99a06e0c 100644 --- a/api/v1/swagger/definitions/sip2_account.yaml +++ b/api/v1/swagger/definitions/sip2_account.yaml @@ -209,6 +209,11 @@ properties: type: - array - 'null' + sort_bin_mappings: + description: Related sort_bin_mappings embed + type: + - array + - 'null' system_preference_overrides: description: Related system_preference_overrides embed type: diff --git a/api/v1/swagger/paths/sip2_accounts.yaml b/api/v1/swagger/paths/sip2_accounts.yaml index 9f8588f536..97d7d4a9ea 100644 --- a/api/v1/swagger/paths/sip2_accounts.yaml +++ b/api/v1/swagger/paths/sip2_accounts.yaml @@ -27,6 +27,7 @@ - item_fields - custom_patron_fields - patron_attributes + - sort_bin_mappings - system_preference_overrides collectionFormat: csv - $ref: "../swagger.yaml#/parameters/match" @@ -149,6 +150,7 @@ - item_fields - custom_patron_fields - patron_attributes + - sort_bin_mappings - system_preference_overrides collectionFormat: csv responses: diff --git a/installer/data/mysql/atomicupdate/bug_37893.pl b/installer/data/mysql/atomicupdate/bug_37893.pl index 0423e1d1d5..1d6df36d6e 100755 --- a/installer/data/mysql/atomicupdate/bug_37893.pl +++ b/installer/data/mysql/atomicupdate/bug_37893.pl @@ -229,6 +229,22 @@ return { ) if $item_field; } + # Accounts sort bin mappings + my @sort_bin_mappings = + ref $SIPconfig->{accounts}->{$account_key}->{sort_bin_mapping} eq "ARRAY" + ? @{ $SIPconfig->{accounts}->{$account_key}->{sort_bin_mapping} } + : ( $SIPconfig->{accounts}->{$account_key}->{sort_bin_mapping} ); + + my $insert_sort_bin_mappings = $dbh->prepare( + q{INSERT IGNORE INTO sip_account_sort_bin_mappings (sip_account_id, mapping) VALUES (?, ?)}); + + foreach my $sort_bin_mapping (@sort_bin_mappings) { + $insert_sort_bin_mappings->execute( + $new_account_id, + $sort_bin_mapping->{mapping} + ) if $sort_bin_mapping; + } + # Accounts system preference overrides my @account_system_preference_overrides = ref $SIPconfig->{accounts}->{$account_key}->{syspref_overrides} eq "ARRAY" diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index b146316b3c..3d64b6439a 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -6210,6 +6210,24 @@ CREATE TABLE `sip_account_item_fields` ( -- Table structure for table `sip_account_system_preference_overrides` -- +DROP TABLE IF EXISTS `sip_account_sort_bin_mappings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `sip_account_sort_bin_mappings` ( + `sip_account_sort_bin_mapping_id` int(11) NOT NULL AUTO_INCREMENT, + `sip_account_id` int(11) NOT NULL COMMENT 'Foreign key to sip_accounts.sip_account_id', + `mapping` varchar(255) NOT NULL COMMENT 'The mapping definition', + PRIMARY KEY (`sip_account_sort_bin_mapping_id`), + UNIQUE KEY `sip_account` (`sip_account_sort_bin_mapping_id`,`sip_account_id`), + KEY `sip_account_sort_bin_mappings_ibfk_1` (`sip_account_id`), + CONSTRAINT `sip_account_sort_bin_mappings_ibfk_1` FOREIGN KEY (`sip_account_id`) REFERENCES `sip_accounts` (`sip_account_id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `sip_account_system_preference_overrides` +-- + DROP TABLE IF EXISTS `sip_account_system_preference_overrides`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; diff --git a/koha-tmpl/intranet-tmpl/prog/js/fetch/sip2-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/fetch/sip2-api-client.js index f9929588a2..327ed5adc7 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/fetch/sip2-api-client.js +++ b/koha-tmpl/intranet-tmpl/prog/js/fetch/sip2-api-client.js @@ -49,7 +49,7 @@ export class SIP2APIClient { endpoint: "accounts/" + id, headers: { "x-koha-embed": - "custom_item_fields,item_fields,custom_patron_fields,patron_attributes,system_preference_overrides", + "custom_item_fields,item_fields,custom_patron_fields,patron_attributes,sort_bin_mappings,system_preference_overrides", }, }), getAll: params => diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/SIP2/SIP2AccountResource.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/SIP2/SIP2AccountResource.vue index 67eea5dbd7..ec0fb37dc9 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/SIP2/SIP2AccountResource.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/SIP2/SIP2AccountResource.vue @@ -605,6 +605,47 @@ export default { }, ], }, + { + name: "sort_bin_mappings", + type: "relationshipWidget", + showElement: { + type: "table", + columnData: "sort_bin_mappings", + hidden: account => !!account.sort_bin_mappings?.length, + columns: [ + { + name: __("Mapping"), + value: "mapping", + }, + ], + }, + group: __("SIP response mappings"), + componentProps: { + resourceRelationships: { + resourceProperty: "sort_bin_mappings", + }, + relationshipStrings: { + nameLowerCase: __("sort bin mapping"), + nameUpperCase: __("Sort bin mapping"), + namePlural: __("sort bin mappings"), + }, + newRelationshipDefaultAttrs: { + type: "object", + value: { + mapping: null, + }, + }, + }, + relationshipFields: [ + { + name: "mapping", + required: true, + type: "text", + placeholder: "CPL:location:eq:OFFICE:2", + label: __("Mapping"), + }, + ], + }, { name: "system_preference_overrides", type: "relationshipWidget",