From c96409dfbc1a4e7d90530b7dcf4c65b612dbcdb8 Mon Sep 17 00:00:00 2001 From: Pedro Amorim Date: Fri, 25 Jul 2025 13:11:05 +0000 Subject: [PATCH] Bug 40529: Add hold group targets logic Hold group target hold: The hold that is set as the hold group's target. If a hold group has a hold target, subsequent check-ins that would 'trap' items to the remaining holds in the group are instead skipped. Signed-off-by: Andrew Fuerste Henry --- Koha/Hold.pm | 18 +++++++++++++ Koha/HoldGroup.pm | 16 ++++++++++++ api/v1/swagger/definitions/hold_group.yaml | 3 +++ .../bug_40529_-_hold_group_table_target.pl | 25 +++++++++++++++++++ installer/data/mysql/kohastructure.sql | 14 +++++++++++ koha-tmpl/intranet-tmpl/prog/js/holds.js | 8 ++++++ svc/holds | 1 + 7 files changed, 85 insertions(+) create mode 100755 installer/data/mysql/atomicupdate/bug_40529_-_hold_group_table_target.pl diff --git a/Koha/Hold.pm b/Koha/Hold.pm index efb5b916c5b..252a8bf3ede 100644 --- a/Koha/Hold.pm +++ b/Koha/Hold.pm @@ -271,6 +271,24 @@ sub cleanup_hold_group { } } +=head3 is_hold_group_target + +$self->is_hold_group_target; + +Returns whether this hold is its hold group target + +=cut + +sub is_hold_group_target { + my ($self) = @_; + + return 1 + if $self->hold_group + && $self->hold_group->target_hold_id + && $self->hold_group->target_hold_id eq $self->reserve_id; + return 0; +} + =head3 set_transfer =cut diff --git a/Koha/HoldGroup.pm b/Koha/HoldGroup.pm index 864056f4431..78d6db6391d 100644 --- a/Koha/HoldGroup.pm +++ b/Koha/HoldGroup.pm @@ -78,6 +78,22 @@ sub holds { return Koha::Holds->_new_from_dbic($holds_rs); } +=head3 target_hold_id + + $holds = $hold_group->target_hold_id + +Return the target_hold_id + +=cut + +sub target_hold_id { + my ($self) = @_; + + return unless $self->_result->hold_group_target_hold; + + return $self->_result->hold_group_target_hold->reserve_id; +} + =head3 _type =cut diff --git a/api/v1/swagger/definitions/hold_group.yaml b/api/v1/swagger/definitions/hold_group.yaml index 271c262b58b..4f122579503 100644 --- a/api/v1/swagger/definitions/hold_group.yaml +++ b/api/v1/swagger/definitions/hold_group.yaml @@ -10,6 +10,9 @@ properties: visual_hold_group_id: type: integer description: Visual ID for this hold group, in the context of the related patron + target_hold_id: + type: integer + description: Target hold ID of this hold group holds: type: - array diff --git a/installer/data/mysql/atomicupdate/bug_40529_-_hold_group_table_target.pl b/installer/data/mysql/atomicupdate/bug_40529_-_hold_group_table_target.pl new file mode 100755 index 00000000000..4d064351362 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_40529_-_hold_group_table_target.pl @@ -0,0 +1,25 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "40529", + description => "Add 'hold_groups_target_hold_id' column to hold_groups", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + unless ( TableExists('hold_group_target_holds') ) { + $dbh->do( + q{ + CREATE TABLE hold_group_target_holds ( + `hold_group_id` int unsigned NOT NULL UNIQUE COMMENT 'foreign key, linking this to the hold_groups table', + `reserve_id` int(11) DEFAULT NULL UNIQUE COMMENT 'foreign key, linking this to the reserves table', + CONSTRAINT `hold_group_target_holds_ibfk_1` FOREIGN KEY (`hold_group_id`) REFERENCES `hold_groups` (`hold_group_id`) ON DELETE CASCADE, + CONSTRAINT `hold_group_target_holds_ibfk_2` FOREIGN KEY (`reserve_id`) REFERENCES `reserves` (`reserve_id`) ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + } + ); + say_success( $out, "Added table 'hold_group_target_holds'" ); + } + }, +}; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 0c333a6ad4a..f6904a300f7 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -5113,6 +5113,20 @@ CREATE TABLE `old_issues` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `hold_group_target_holds` +-- +DROP TABLE IF EXISTS `hold_group_target_holds`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE hold_group_target_holds ( + `hold_group_id` int unsigned NOT NULL UNIQUE COMMENT 'foreign key, linking this to the hold_groups table', + `reserve_id` int(11) DEFAULT NULL UNIQUE COMMENT 'foreign key, linking this to the reserves table', + CONSTRAINT `hold_group_target_holds_ibfk_1` FOREIGN KEY (`hold_group_id`) REFERENCES `hold_groups` (`hold_group_id`) ON DELETE CASCADE, + CONSTRAINT `hold_group_target_holds_ibfk_2` FOREIGN KEY (`reserve_id`) REFERENCES `reserves` (`reserve_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `old_reserves` -- diff --git a/koha-tmpl/intranet-tmpl/prog/js/holds.js b/koha-tmpl/intranet-tmpl/prog/js/holds.js index 93108133a8d..4b449f2741a 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/holds.js +++ b/koha-tmpl/intranet-tmpl/prog/js/holds.js @@ -259,6 +259,14 @@ $(document).ready(function () { ""; } + if (oObj.is_hold_group_target) { + var link = __("target of hold group"); + title += + '
(' + + link + + ")"; + } + return title; }, }, diff --git a/svc/holds b/svc/holds index 864841851a9..4170f4585b2 100755 --- a/svc/holds +++ b/svc/holds @@ -115,6 +115,7 @@ while ( my $h = $holds_rs->next() ) { itemtype_limit => $itemtype_limit, hold_group_id => $h->hold_group_id, visual_hold_group_id => $h->hold_group ? $h->hold_group->visual_hold_group_id : q{}, + is_hold_group_target => $h->is_hold_group_target, reservedate_formatted => $h->reservedate() ? output_pref( { dt => dt_from_string( $h->reservedate() ), dateonly => 1 } ) : q{}, -- 2.39.5