From f26f323aee480bb99bf94f3c6f944c1cddf15964 Mon Sep 17 00:00:00 2001 From: Lucas Gass Date: Fri, 3 Apr 2026 18:38:18 +0000 Subject: [PATCH 01/41] Bug 42262: encodeURIComponent for the 006 value To test: 1- have a MARC record with Type of Material "BKS - Books" that does not have an 006 defined (biblio 1 in the KTD default data will work) 2- edit the biblio in the basic editor 3- open the tag editor for the 006 4- observe that the values along the top of the tag editor window show a value of "" (blank) in position 17 5- click Save in the tag editor window 6- confirm that the values in the 006 tag end with a space 7- open the 006 tag editor again 8- observe that the values along the top of the tag editor window no longer show any value for position 17. Instead, they end with the zero in position 16 9- click Save in the tag editor window 10- confirm that the values in the 006 tag now end with a zero, not followed by a space 11- save your biblio 12- edit the biblio in the basic editor again, get warning "The following fixed-length control field(s) have an invalid length: 006. Please fix." 13- APPLY PATCH and restart_all 14. Try editing the 006 value again, the whitespace should be preserved and you get no error. Signed-off-by: Justin Swink Signed-off-by: Andrew Fuerste Henry Signed-off-by: Lucas Gass (cherry picked from commit 1a0501f5e8110cda80d5d24fd7e524f3553340bf) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- cataloguing/value_builder/marc21_field_006.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cataloguing/value_builder/marc21_field_006.pl b/cataloguing/value_builder/marc21_field_006.pl index 658af3ed1e..c8718ecb0f 100755 --- a/cataloguing/value_builder/marc21_field_006.pl +++ b/cataloguing/value_builder/marc21_field_006.pl @@ -37,7 +37,7 @@ my $builder = sub { function Click$function_name(event) { defaultvalue=document.getElementById(event.data.id).value; - newin=window.open(\"../cataloguing/plugin_launcher.pl?plugin_name=marc21_field_006.pl&index=\"+ event.data.id +\"&result=\"+defaultvalue,\"tag_editor\",'width=1000,height=600,toolbar=false,scrollbars=yes'); + newin=window.open(\"../cataloguing/plugin_launcher.pl?plugin_name=marc21_field_006.pl&index=\"+ event.data.id +\"&result=\"+encodeURIComponent(defaultvalue),\"tag_editor\",'width=1000,height=600,toolbar=false,scrollbars=yes'); } From ea6fd886a0a1f8b92a5fef00b79be6505586f05b Mon Sep 17 00:00:00 2001 From: Hammat Wele Date: Wed, 4 Mar 2026 21:23:42 +0000 Subject: [PATCH 02/41] Bug 41690: Add MARC21 245 (subtitle) to Cite option The "Cite" option in the OPAC is missing the subtitle (245) in MARC21. To recreate: 1. Add a record or find a record with a subtitle (in KTD, biblionumber 58 has a 245 http://localhost:8081/cgi-bin/koha/catalogue/MARCdetail.pl?biblionumber=58 2. In the OPAC, go to the record http://localhost:8080/cgi-bin/koha/opac-detail.pl?biblionumber=58 3. Click "Cite" --> The subtitle is not in any of the citations 4. Apply the patch 5. Repeat step 2 and 3 --> The subtitle is now shown Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass (cherry picked from commit 412e4e4d95eed7577b2768221848e663bd4821d5) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- C4/Record.pm | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/C4/Record.pm b/C4/Record.pm index febb1228ae..43f354d111 100644 --- a/C4/Record.pm +++ b/C4/Record.pm @@ -931,6 +931,7 @@ sub marc2cites { if ( $marcflavour eq "UNIMARC" ) { %publication = ( title => $record->subfield( "200", "a" ) || "", + subtitle => $record->subfield( "200", "e" ) || "", place => $record->subfield( "210", "a" ) || "", publisher => $record->subfield( "210", "c" ) || "", date => $record->subfield( "210", "d" ) || $record->subfield( "210", "h" ) || "" @@ -938,6 +939,7 @@ sub marc2cites { } else { %publication = ( title => $record->subfield( "245", "a" ) || "", + subtitle => $record->subfield( "245", "b" ) || "", place => $record->subfield( "264", "a" ) || $record->subfield( "260", "a" ) || "", publisher => $record->subfield( "264", "b" ) || $record->subfield( "260", "b" ) || "", date => $record->subfield( "264", "c" ) @@ -978,13 +980,16 @@ sub marc2cites { if ( $publication{date} ) { $cites{'Harvard'} .= ' (' . $publication{'date'} . '). '; $cites{'Chicago'} .= ' ' . $publication{'date'} . '. '; - $cites{'MLA'} .= ' ' . $publication{'title'} . '. '; - $cites{'APA'} .= ' (' . $publication{'date'} . '). '; + $cites{'MLA'} .= + ' ' . $publication{'title'} . ( $publication{'subtitle'} ? ': ' . $publication{'subtitle'} : '' ) . '. '; + $cites{'APA'} .= ' (' . $publication{'date'} . '). '; } - $cites{'Harvard'} .= $publication{'title'} . '. '; - $cites{'Chicago'} .= $publication{'title'} . '. '; - $cites{'MLA'} .= $publication{'place'} . ': '; - $cites{'APA'} .= $publication{'title'} . '. '; + $cites{'Harvard'} .= + $publication{'title'} . ( $publication{'subtitle'} ? ': ' . $publication{'subtitle'} : '' ) . '. '; + $cites{'Chicago'} .= + $publication{'title'} . ( $publication{'subtitle'} ? ': ' . $publication{'subtitle'} : '' ) . '. '; + $cites{'MLA'} .= $publication{'place'} . ': '; + $cites{'APA'} .= $publication{'title'} . ( $publication{'subtitle'} ? ': ' . $publication{'subtitle'} : '' ) . '. '; $cites{'Harvard'} .= $publication{'place'} . ': '; $cites{'Chicago'} .= $publication{'place'} . ': '; $cites{'MLA'} .= $publication{'publisher'} . '. '; From 9b394ddb7a61b75545fb953aa6d5870e7ed3b84b Mon Sep 17 00:00:00 2001 From: Hammat Wele Date: Fri, 6 Mar 2026 20:46:47 +0000 Subject: [PATCH 03/41] Bug 41690: (follow-up) Add test Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass (cherry picked from commit a0b92c0bb6b48957c5b15c076ecbfba682518b0b) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- t/db_dependent/Record.t | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/t/db_dependent/Record.t b/t/db_dependent/Record.t index 487e42f6c3..fb5f3f327d 100755 --- a/t/db_dependent/Record.t +++ b/t/db_dependent/Record.t @@ -3,7 +3,7 @@ use Modern::Perl; use Test::NoWarnings; -use Test::More tests => 16; +use Test::More tests => 17; use MARC::Record; use t::lib::Mocks; @@ -152,3 +152,11 @@ is( $entity[0], "Björn", "Html umlauts" ); $marc->field('260')->add_subfields( a => 'Hogwarts' ); my $cites = marc2cites($marc); is( $cites->{'Chicago'}, 'Rowling J.K, . 2011. Harry potter. Hogwarts: Reprints.', 'testing marc2cites' ); + +my $field245 = $marc->field('245'); +$field245->add_subfields( 'b' => 'the cursed child' ); +$cites = marc2cites($marc); +is( + $cites->{'Chicago'}, 'Rowling J.K, . 2011. Harry potter: the cursed child. Hogwarts: Reprints.', + 'testing marc2cites' +); From 4e7d0ea5206af4a7bc2ab93c8902b0b59e765fa5 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 12 May 2026 12:22:11 +0200 Subject: [PATCH 04/41] Bug 42475: Fix opac vs OPAC Correct "opac" with "OPAC" in the pref file Test plan: git grep opac **/*.pref and confirm that there is no relevant occurrences in the output (i.e. no strings displayed on the UI) Signed-off-by: Owen Leonard Signed-off-by: Laura_Escamilla Signed-off-by: David Nind Signed-off-by: Lucas Gass (cherry picked from commit b860c04197770bb0b488e9c77891cb953cc3408b) Signed-off-by: Baptiste Wojtkowski Signed-off-by: Wainui Witika-Park --- .../prog/en/modules/admin/preferences/enhanced_content.pref | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref index 1f088136f4..06033a818a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/enhanced_content.pref @@ -103,7 +103,7 @@ Enhanced content: - - Access Novelist Select using user profile - pref: NovelistSelectProfile - - on the opac + - on the OPAC - - Access Novelist Select using user profile - pref: NovelistSelectStaffProfile From e7b5d78a6edd8efbb3c99f9c09d0393a69aaf21c Mon Sep 17 00:00:00 2001 From: Owen Leonard Date: Tue, 12 May 2026 07:05:39 -0400 Subject: [PATCH 05/41] Bug 42475: (follow-up) Fix a couple more instances of 'opac' Signed-off-by: Laura_Escamilla Signed-off-by: David Nind Signed-off-by: Lucas Gass (cherry picked from commit e2f5afe100481b5364f4a9962caba9f3d6bee13c) Signed-off-by: Baptiste Wojtkowski Signed-off-by: Wainui Witika-Park --- .../prog/en/modules/admin/preferences/cataloguing.pref | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref index 9c62cae068..53fe8f0755 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref @@ -105,7 +105,7 @@ Cataloging: choices: 1: specific item 0: bibliographic record - - as the authoritative item type (for determining circulation and fine rules, for displaying an item type icon on either opac detail or results page, etc). + - as the authoritative item type (for determining circulation and fine rules, for displaying an item type icon on either OPAC detail or results page, etc). - - Map the MARC subfields - pref: itemcallnumber @@ -284,7 +284,7 @@ Cataloging: - pref: OpacSuppressionByIPRange class: short - (Leave blank if not used. Define a range like 192.168..) - -
Redirect the opac detail page for suppressed records to + -
Redirect the OPAC detail page for suppressed records to - pref: OpacSuppressionRedirect choices: 1: "an explanatory page ('This record is blocked')." From 8943833fb10a15ff371ac635f9e937fdb8bd74a1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 9 Apr 2026 02:56:39 +0000 Subject: [PATCH 06/41] Bug 42317: Update minimum version for MARC::File::XML This patch updates cpanfile to reflect the real minimum version needed for MARC::File::XML. This is particularly important due to vulnerabilities in version 1.0.1 Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: mason james Signed-off-by: Lucas Gass (cherry picked from commit 00655de4d0becf5623e81f0cf80359d61f01ff4d) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- cpanfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpanfile b/cpanfile index 84d6e4ede0..31775489d4 100644 --- a/cpanfile +++ b/cpanfile @@ -72,7 +72,7 @@ requires 'Locale::Messages', '1.20'; requires 'Locale::PO', '0.24'; requires 'Log::Log4perl', '1.29'; requires 'MARC::Charset', '0.98'; -requires 'MARC::File::XML', 'v1.0.1'; +requires 'MARC::File::XML', 'v1.0.5'; requires 'MARC::Lint', 'v1.52'; requires 'MARC::Record', 'v2.0.6'; requires 'MARC::Record::MiJ', '0.04'; From 768f2a48825a02a5c73bf232b1d8e8ad247fbf3f Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Thu, 22 Jan 2026 16:13:44 +0100 Subject: [PATCH 07/41] Bug 40744: Ignore --del-exp-selfreg if pref is not set If PatronSelfRegistration we should ignore (i.e. do nothing) if --del-exp-selfreg is passed to cleanup_database.pl It prevents the script to warn that the pref is not set. Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Martin Renvoize (cherry picked from commit d331c7aba8e5ae252f63560b51fe22ae963f15c2) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- misc/cronjobs/cleanup_database.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/cronjobs/cleanup_database.pl b/misc/cronjobs/cleanup_database.pl index 771846adfc..2299e59cc5 100755 --- a/misc/cronjobs/cleanup_database.pl +++ b/misc/cronjobs/cleanup_database.pl @@ -524,7 +524,7 @@ if ($verbose) { say $confirm ? sprintf( "Deleted %d patrons", $count ) : sprintf( "%d patrons would have been deleted", $count ); } -if ($pExpSelfReg) { +if ( $pExpSelfReg && C4::Context->preference('PatronSelfRegistration') ) { try { my $opac_registrations = Koha::Patrons->search->filter_by_expired_opac_registrations->filter_by_safe_to_delete; my $count = $opac_registrations->count; From da718a2a577c698f24f29aac4242010ac562aa68 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 7 Apr 2026 10:20:29 +0200 Subject: [PATCH 08/41] Bug 42277: Remove JS error when viewing a subscription If no orders exist yet, there is a JS error in the console: Uncaught TypeError: can't access property "DataTable", table is undefined Test plan: 0. Do no apply this patch 1. Create a new subscription and go to the detail view 2. Open the console and notice the JS error 3. Apply this patch 4. Confirm that the JS error is gone 5. Create an order from this subscription 6. Confirm that the orders table is displayed Signed-off-by: Owen Leonard Signed-off-by: Brendan Lawlor Signed-off-by: Lucas Gass (cherry picked from commit da121583a4dd3f69406e3f5cde0505b85c186342) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- .../prog/en/modules/serials/subscription-detail.tt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-detail.tt index 6d25533f1a..21f4ffc6dc 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-detail.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/serials/subscription-detail.tt @@ -497,8 +497,8 @@ [% END %] - let table_dt = table.DataTable(); - $("#hide_received_orders").click(function(e){ + let table_dt = table?.DataTable(); + $("#hide_received_orders").click(function (e) { e.preventDefault(); table_dt.columns(4).search('^$', {regex: true}).draw(); // Not empty "Receive date" columns }); From 47bb99149685d8362c443b9a99daa972b8bd971f Mon Sep 17 00:00:00 2001 From: apirak Date: Wed, 6 May 2026 15:05:48 +0700 Subject: [PATCH 09/41] Bug 42545: Koha::Calendar::days_between skips holiday subtraction for end date if time is early In Koha::Calendar::days_between, the holiday-subtraction loop uses a comparison that includes time. If the end_dt is a holiday and its time is earlier than the start_dt time (common in renewals), the loop terminates before processing the end_dt, leading to an extra fine day. This patch truncates both dates to the beginning of the day after cloning and setting the time zone, ensuring the loop correctly processes all calendar days between the two dates. Test Plan: 1. Set 'finesCalendar' syspref to 'noFinesWhenClosed'. 2. Set 'CalculateFinesOnReturn' syspref to 'Yes'. 3. Set 'finesMode' syspref to 'Production'. 4. Define a special holiday for today in the library calendar. 5. Identify an overdue item for a patron. Manually set its 'date_due' in the database to several days ago with a time of 23:59:00. 6. Renew the item today at any time BEFORE 23:59:00 (e.g., 10:00 AM). 7. Observe that an extra day of fine is charged because today (the holiday) was not subtracted. 8. Apply this patch. 9. Repeat the test and observe that the holiday is now correctly subtracted. Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass (cherry picked from commit 9c38d74c98488cabc882fa180927077d9cc8ec86) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- Koha/Calendar.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm index b10ff76fd0..354ed3c307 100644 --- a/Koha/Calendar.pm +++ b/Koha/Calendar.pm @@ -342,9 +342,10 @@ sub days_between { my $end_dt = shift; # Change time zone for date math and swap if needed - $start_dt = $start_dt->clone->set_time_zone('floating'); - $end_dt = $end_dt->clone->set_time_zone('floating'); + $start_dt = $start_dt->clone->set_time_zone('floating')->truncate( to => 'day' ); + $end_dt = $end_dt->clone->set_time_zone('floating')->truncate( to => 'day' ); if ( $start_dt->compare($end_dt) > 0 ) { + ( $start_dt, $end_dt ) = ( $end_dt, $start_dt ); } From cda9dcf2243bf9aa6f72a01f8ce7bcc034607080 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Mon, 18 May 2026 18:16:51 +0100 Subject: [PATCH 10/41] Bug 42545: (QA follow-up) Add POD for _init and _holidays and fix incorrect test expectation The existing 'days: 289 hours, 2 holidays' test asserted 8-1=7 but its own description named 2 holidays. The expected value matched the buggy behaviour (loop exiting before the holiday end date) rather than the correct result. Update to 8-2=6 to reflect the fix. Signed-off-by: Lucas Gass (cherry picked from commit 6ca7c1118beac573e5ed37dfb64161835e0cf41f) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- Koha/Calendar.pm | 14 ++++++++++++++ t/db_dependent/Calendar.t | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm index 354ed3c307..cc71b3926a 100644 --- a/Koha/Calendar.pm +++ b/Koha/Calendar.pm @@ -449,6 +449,20 @@ Koha::Calendar - Object containing a branches calendar =head1 METHODS +=head2 _init + + $calendar->_init(); + +Populates the object with repeatable closed days (weekly and day/month) for the +branch. Called automatically by C. + +=head2 _holidays + + my $holidays = $calendar->_holidays(); + +Returns a hashref of special (one-off) holidays for the branch, keyed by +C date strings. Results are cached. + =head2 new : Create a calendar object my $calendar = Koha::Calendar->new( branchcode => 'MAIN' ); diff --git a/t/db_dependent/Calendar.t b/t/db_dependent/Calendar.t index 0b1c479c3f..0c2ca52165 100755 --- a/t/db_dependent/Calendar.t +++ b/t/db_dependent/Calendar.t @@ -612,7 +612,7 @@ subtest 'hours_between | days_between' => sub { $diff_hours = $calendar->hours_between( $now, $nov_13->clone->subtract( hours => 3 ) )->hours; is( $diff_hours, 8 * 24 - 2 * 24 - 3, 'hours: 289 hours, 2 holidays ' ); $diff_days = $calendar->days_between( $now, $nov_13->clone->subtract( hours => 3 ) )->delta_days; - is( $diff_days, 8 - 1, 'days: 289 hours, 2 holidays' ); + is( $diff_days, 8 - 2, 'days: 289 hours, 2 holidays' ); # Between 5th and 15th $diff_hours = $calendar->hours_between( $now, $nov_15->clone->subtract( hours => 3 ) )->hours; From 8953882d8115cc1001479c8be01170d17a0f4f01 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Mon, 18 May 2026 18:17:00 +0100 Subject: [PATCH 11/41] Bug 42545: (QA follow-up) Add unit tests for holiday subtraction when return time is before due time Adds a dedicated subtest covering the specific scenario: daily loans have a due time of 23:59, so a return earlier in the day on a holiday would previously cause days_between to exit its loop before processing the end date, silently skipping the holiday subtraction. Signed-off-by: Lucas Gass (cherry picked from commit 0a0dcee152093dc98480ecf6349022918006926e) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- t/db_dependent/Calendar.t | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/t/db_dependent/Calendar.t b/t/db_dependent/Calendar.t index 0c2ca52165..15d9e4f173 100755 --- a/t/db_dependent/Calendar.t +++ b/t/db_dependent/Calendar.t @@ -513,7 +513,7 @@ subtest 'hours_between | days_between' => sub { }; subtest 'With holiday' => sub { - plan tests => 2; + plan tests => 3; my $library = $builder->build_object( { class => 'Koha::Libraries' } ); @@ -621,6 +621,35 @@ subtest 'hours_between | days_between' => sub { is( $diff_days, 10 - 2, 'days: 237 hours, 2 holidays' ); }; + subtest 'Bug 42545: holiday on end_dt correctly subtracted when return time is before due time' => sub { + plan tests => 4; + + # Scenario: daily loan (due time 23:59), patron returns/renews before 23:59 on a holiday. + # Before the fix, days_between did not truncate datetimes, so the loop exited before + # reaching the end date when due_time > return_time on the same calendar day. + + # Nov 13 is a Wednesday (holiday). Due at end-of-day, returned early morning. + my $due_endofday = dt_from_string('2019-11-05 23:59:00'); + my $return_on_holiday_early = dt_from_string('2019-11-13 09:34:56'); + + my $diff_days = $calendar->days_between( $due_endofday, $return_on_holiday_early )->delta_days; + is( $diff_days, 8 - 2, 'holiday on end_dt subtracted when return time is before due time (23:59)' ); + + # Same range but returned late (after 23:59 would be next day, so use 23:58) - no regression + my $return_on_holiday_late = dt_from_string('2019-11-13 23:58:00'); + $diff_days = $calendar->days_between( $due_endofday, $return_on_holiday_late )->delta_days; + is( $diff_days, 8 - 2, 'holiday on end_dt subtracted when return time is just before due time' ); + + # Open end date is unaffected either way + my $return_open_early = dt_from_string('2019-11-14 09:34:56'); + $diff_days = $calendar->days_between( $due_endofday, $return_open_early )->delta_days; + is( $diff_days, 9 - 2, 'open end_dt unaffected, 2 holidays still subtracted (early return)' ); + + my $return_open_late = dt_from_string('2019-11-14 23:58:00'); + $diff_days = $calendar->days_between( $due_endofday, $return_open_late )->delta_days; + is( $diff_days, 9 - 2, 'open end_dt unaffected, 2 holidays still subtracted (late return)' ); + }; + }; Time::Fake->reset; From 09a6760a51878962e3004758cf4d68d8383c436d Mon Sep 17 00:00:00 2001 From: Lucas Gass Date: Wed, 20 May 2026 14:48:25 +0000 Subject: [PATCH 12/41] Bug 42545: (RM follow-up) Tidy test file Signed-off-by: Lucas Gass (cherry picked from commit 1ed156ef40de9a760c1030da2b0e3a37a8d4ca07) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- t/db_dependent/Calendar.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/db_dependent/Calendar.t b/t/db_dependent/Calendar.t index 15d9e4f173..7fd26efdc7 100755 --- a/t/db_dependent/Calendar.t +++ b/t/db_dependent/Calendar.t @@ -629,7 +629,7 @@ subtest 'hours_between | days_between' => sub { # reaching the end date when due_time > return_time on the same calendar day. # Nov 13 is a Wednesday (holiday). Due at end-of-day, returned early morning. - my $due_endofday = dt_from_string('2019-11-05 23:59:00'); + my $due_endofday = dt_from_string('2019-11-05 23:59:00'); my $return_on_holiday_early = dt_from_string('2019-11-13 09:34:56'); my $diff_days = $calendar->days_between( $due_endofday, $return_on_holiday_early )->delta_days; From a45a642f35f9d7f56ec68708b1c092c9cdbf1ec2 Mon Sep 17 00:00:00 2001 From: Andreas Roussos Date: Mon, 9 Feb 2026 15:49:03 +0000 Subject: [PATCH 13/41] Bug 41337: Add missing Bash variable to `koha-create` When creating a new Koha instance using the two-step workflow (`koha-create --request-db `, followed by `koha-create --populate-db `), some log files under /var/log/koha// end up with incorrect ownership. Specifically, intranet-error.log and opac-error.log are owned by root:root instead of -koha:-koha. This patch fixes that. Test plan (tailored for KTD): 1) Before applying this patch, run the following commands inside your KTD Koha container: $ sudo koha-create --request-db test1 $ SQLPASS=`sudo grep password: test1-db-request.txt | cut -c 16-` $ mysql -hdb -uroot -ppassword -e "CREATE DATABASE koha_test1;" $ mysql -hdb -uroot -ppassword -e "GRANT ALL PRIVILEGES ON koha_test1.* TO 'koha_test1'@'%' IDENTIFIED BY '${SQLPASS}';" $ mysql -hdb -uroot -ppassword -e "FLUSH PRIVILEGES;" $ sudo koha-create --populate-db test1 $ ls -l /var/log/koha/test1/ total 8 -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:35 indexer-error.log -rw-r--r-- 1 test1-koha test1-koha 1278 Feb 9 15:35 indexer-output.log -rw-r--r-- 1 root root 0 Feb 9 15:35 intranet-error.log -rw-r--r-- 1 root root 0 Feb 9 15:35 opac-error.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:35 worker-error.log -rw-r--r-- 1 test1-koha test1-koha 1828 Feb 9 15:35 worker-output.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:35 zebra-error.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:35 zebra-output.log Notice the incorrect user/group ownership on two files: `intranet-error.log` and `opac-error.log`. 2) Apply this patch, remove the `test1` instance along with the database request text file, and copy the modified script to its system-wide location: $ sudo koha-remove test1 $ sudo rm test1-db-request.txt $ sudo cp debian/scripts/koha-create /usr/sbin/koha-create 3) Repeat the commands in Step 1. This time, the output of the last command should resemble the following: total 8 -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:42 indexer-error.log -rw-r--r-- 1 test1-koha test1-koha 1520 Feb 9 15:42 indexer-output.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:42 intranet-error.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:42 opac-error.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:42 worker-error.log -rw-r--r-- 1 test1-koha test1-koha 1828 Feb 9 15:42 worker-output.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:42 zebra-error.log -rw-r--r-- 1 test1-koha test1-koha 0 Feb 9 15:42 zebra-output.log All files should now have the correct user/group ownership. Signed-off-by: Brendan Lawlor Signed-off-by: Jan Kissig Signed-off-by: Lucas Gass (cherry picked from commit 7ee861e25626f337690d0eef625f62b83be12e5a) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- debian/scripts/koha-create | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/scripts/koha-create b/debian/scripts/koha-create index 6eeb1fe2a9..06c7cfa232 100755 --- a/debian/scripts/koha-create +++ b/debian/scripts/koha-create @@ -896,6 +896,8 @@ fi if [ "$op" = create ] || [ "$op" = populate ] || [ "$op" = use ] then + username="$name-koha" + # Reconfigure Apache. if ! { a2ensite "$name" > /dev/null 2>&1 || From d12c78f59627339ce3f031752044a7bd3837b09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Cohen=20Arazi?= Date: Wed, 4 Mar 2026 10:11:43 -0300 Subject: [PATCH 14/41] Bug 40481: Fix OPAC MARC detail showing hidden items The OPAC MARC detail view (opac-MARCdetail.pl) uses $record->fields() to build the items table. This pulls item fields from the embedded MARC record, bypassing the OPACHiddenItems filtering done by filter_by_visible_in_opac. This patch replaces the $record->fields() call with the already-filtered $items resultset, converting each Koha::Item back to a MARC::Field via as_marc_field. Test plan: 1. Apply patch, do not restart plack yet 2. Setup: $ ktd --shell k$ koha-mysql kohadev <<< "UPDATE systempreferences SET value = 'damaged: [1]' WHERE variable = 'OpacHiddenItems';" k$ koha-mysql kohadev <<< "UPDATE items SET damaged = 1 WHERE biblionumber = 416 LIMIT 1;" k$ flush_memcached 3. Point your browser to the OPAC MARC detail view: http://kohadev.localhost/cgi-bin/koha/opac-MARCdetail.pl?biblionumber=416 => FAIL: The damaged item is displayed in the items table 4. Restart plack: k$ restart_all 5. Refresh the page => SUCCESS: The damaged item is no longer displayed 6. Undo the test data: k$ koha-mysql kohadev <<< "UPDATE items SET damaged = 0 WHERE biblionumber = 416;" k$ koha-mysql kohadev <<< "UPDATE systempreferences SET value = '' WHERE variable = 'OpacHiddenItems';" k$ flush_memcached 7. Sign off :-D Signed-off-by: David Nind Signed-off-by: David Cook Signed-off-by: Martin Renvoize (cherry picked from commit 3f7c9f0f6ce7b53e027f9ca77543f244390110ca) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- opac/opac-MARCdetail.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opac/opac-MARCdetail.pl b/opac/opac-MARCdetail.pl index 621c12dcbc..1ba0a6e4ee 100755 --- a/opac/opac-MARCdetail.pl +++ b/opac/opac-MARCdetail.pl @@ -300,7 +300,8 @@ for ( my $tabloop = 0 ; $tabloop <= 9 ; $tabloop++ ) { # warning : we may have different number of columns in each row. Thus, we first build a hash, complete it if necessary # then construct template. # $record has already had all the item fields filtered above. -my @fields = $record->fields(); +$items->reset(); +my @fields = map { $_->as_marc_field } $items->as_list; my %witness; #---- stores the list of subfields used at least once, with the "meaning" of the code my @item_subfield_codes; my @item_loop; From 35aee9a0941f437bc6de2b72b9c5a4ba6483a4bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Cohen=20Arazi?= Date: Wed, 4 Mar 2026 10:16:43 -0300 Subject: [PATCH 15/41] Bug 40481: (follow-up) Simplify item loop in OPAC MARC detail Now that the item loop only processes item fields from the filtered $items resultset, several checks and patterns become unnecessary. Changes: - Remove dead checks: tag < 10 and tab != 10 guards - Resolve $tagslib->{$item_tag} once instead of per-subfield - Destructure ($code, $value) instead of indexed $subf[$i][0/1] - Replace per-subfield grep over date kohafields with a hash lookup - Remove redundant second $tagslib lookup for $kohafield - Collapse repeatable if/else into a ternary No functional changes. Test plan: 1. Apply patch 2. Run the same test plan as the previous patch => SUCCESS: Behavior is identical 3. Sign off :-D Signed-off-by: David Nind Signed-off-by: David Cook Signed-off-by: Martin Renvoize (cherry picked from commit 573550aec7d1682840c1aac0c5ee459701a947c9) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- opac/opac-MARCdetail.pl | 53 ++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/opac/opac-MARCdetail.pl b/opac/opac-MARCdetail.pl index 1ba0a6e4ee..dd7cacbcb5 100755 --- a/opac/opac-MARCdetail.pl +++ b/opac/opac-MARCdetail.pl @@ -294,54 +294,43 @@ for ( my $tabloop = 0 ; $tabloop <= 9 ; $tabloop++ ) { $template->param( "tab" . $tabloop . "XX" => \@loop_data ); } -# now, build item tab ! -# the main difference is that datas are in lines and not in columns : thus, we build the first, then the values... -# loop through each tag -# warning : we may have different number of columns in each row. Thus, we first build a hash, complete it if necessary -# then construct template. -# $record has already had all the item fields filtered above. +# Now, build item tab! +# Data is in rows (one per item) not columns: build headers (%witness) and row data (@item_loop). $items->reset(); -my @fields = map { $_->as_marc_field } $items->as_list; -my %witness; #---- stores the list of subfields used at least once, with the "meaning" of the code +my @fields = map { $_->as_marc_field } $items->as_list; +my $item_tag = $fields[0] ? $fields[0]->tag() : undef; +my $item_tagslib = $item_tag ? $tagslib->{$item_tag} : {}; +my %witness; my @item_subfield_codes; my @item_loop; + +my %date_fields = map { $_ => 1 } + qw( items.dateaccessioned items.onloan items.datelastseen items.datelastborrowed items.replacementpricedate ); + foreach my $field (@fields) { - next if ( $field->tag() < 10 ); - my @subf = $field->subfields; my $item; - # loop through each subfield - for my $i ( 0 .. $#subf ) { - my $sf_def = $tagslib->{ $field->tag() }->{ $subf[$i][0] }; - next if ( ( $sf_def->{tab} || 0 ) != 10 ); + for my $subf ( $field->subfields ) { + my ( $code, $value ) = @$subf; + my $sf_def = $item_tagslib->{$code}; next if ( ( $sf_def->{hidden} || 0 ) > 0 ); - push @item_subfield_codes, $subf[$i][0]; - $witness{ $subf[$i][0] } = $sf_def->{lib}; + push @item_subfield_codes, $code; + $witness{$code} = $sf_def->{lib}; # Allow repeatables (BZ 13574) - if ( $item->{ $subf[$i][0] } ) { - $item->{ $subf[$i][0] } .= ' | '; - } else { - $item->{ $subf[$i][0] } = q{}; - } + $item->{$code} = ( $item->{$code} ) ? $item->{$code} . ' | ' : q{}; if ( $sf_def->{isurl} ) { - $item->{ $subf[$i][0] } .= "$subf[$i][1]"; + $item->{$code} .= "$value"; } elsif ( $sf_def->{kohafield} eq "biblioitems.isbn" ) { - $item->{ $subf[$i][0] } .= $subf[$i][1]; + $item->{$code} .= $value; } else { - $item->{ $subf[$i][0] } .= GetAuthorisedValueDesc( - $field->tag(), $subf[$i][0], - $subf[$i][1], '', $tagslib, '', 'opac' - ) // q{}; + $item->{$code} .= GetAuthorisedValueDesc( $item_tag, $code, $value, '', $tagslib, '', 'opac' ) // q{}; } - my $kohafield = $tagslib->{ $field->tag() }->{ $subf[$i][0] }->{kohafield}; - $item->{ $subf[$i][0] } = output_pref( { str => $item->{ $subf[$i][0] }, dateonly => 1 } ) - if grep { $kohafield eq $_ } - qw( items.dateaccessioned items.onloan items.datelastseen items.datelastborrowed items.replacementpricedate ); - + $item->{$code} = output_pref( { str => $item->{$code}, dateonly => 1 } ) + if $date_fields{ $sf_def->{kohafield} // q{} }; } push @item_loop, $item if $item; } From 46a8ba6dafd9a4d9c0d75b66cb2462e72f63aa0a Mon Sep 17 00:00:00 2001 From: Laura_Escamilla Date: Fri, 3 Apr 2026 14:37:29 +0000 Subject: [PATCH 16/41] Bug 42236: Add accessible label to OPAC user lists actions column To recreate: 1. Log in to the OPAC 2. Create at least 1 list 3. Go to the "Your lists" page (opac-userlists) 4. Inspect the table header for the Edit/Delete column 5. Confirm the header contains no text Test the patch: 1. Apply the patch 2. Repeat steps 1-3 3. Inspect the table header for the Edit/Delete column 4. Confirm the header now contains accessible text 5. Confirm Edit and Delete actions still function as expected 6. Run an accessibility checker and confirm the issue is resolved 7. Sign off and have a wonderful day! :D Signed-off-by: John Vinke Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass (cherry picked from commit 88676495e04423292308dbde090e40eee92f859c) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-shelves.tt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-shelves.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-shelves.tt index fcdbde5937..38f66bf5f3 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-shelves.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-shelves.tt @@ -720,7 +720,7 @@ Contents Type Modification date -   + Actions From 1b837562b2a8a54d74d202556138d774209db9e5 Mon Sep 17 00:00:00 2001 From: Hammat Wele Date: Fri, 24 Oct 2025 20:03:00 +0000 Subject: [PATCH 17/41] Bug 41102: Error 500 on the About page when biblioserver Zebra configuration is missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When either the entry or the section is not present in koha-conf.xml, the Staff interface > About page triggers a 500 Internal Server Error. Test plan: 1. Edit koha-conf.xml and Comment out: 2. Restart Apache: sudo systemctl restart apache2 (or restart_all) 3. Go to Intranet > About ==> Internal Server Error (500) 4. Now restore the line and instead comment out the entire ... block. (Note that the commenting around Confirm that the purchase suggestion from step 2 is still shown 5. Clear the "search" field and search for the author's first or last name --> Confirm that the suggestion from step 2 is still shown 6. Use the "search" field to search for each of the other pieces of information filled out in step 2 --> Confirm that the suggestion is still shown for each search Signed-off-by: David Nind Signed-off-by: Andrew Fuerste Henry Signed-off-by: Lucas Gass (cherry picked from commit bf7522b67ccaec1eb089f6bf57896525f887b413) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- .../intranet-tmpl/prog/en/modules/suggestion/suggestion.tt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt index 93d3da8c42..d47903b2df 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/suggestion/suggestion.tt @@ -1349,7 +1349,7 @@ } }, { - data: "me.title", + data: "me.title:me.author:me.copyrightdate:me.volumedesc:me.isbn:me.publishercode:me.publicationyear:me.place:me.collectiontitle:me.itemtype:me.note", searchable: true, orderable: true, render: function (data, type, row, meta) { From fd200814291c7d6ce211bebf757fe52faf6ec3bb Mon Sep 17 00:00:00 2001 From: Emmi Takkinen Date: Mon, 25 Apr 2022 10:04:21 +0300 Subject: [PATCH 38/41] Bug 29768: Do not hide guarantor name from memberentry.pl Syspref "hidepatronname" currently hides guarantors name on memberentry.pl. This is inconsistent since name isn't hidden e.g. on moremember.pl and staff can already see patrons other personal information during edit. To test: 1) Disable syspref "hidepatronname" 2) Edit guarantee patrons information => Field "Guarantor" only shows guarantors cardnumber (or is empty if guarantor has no cardnumber) 3) Apply patch => Guarantors name is now displayed (as a hyperlink) Also confirm hidepatronname still works as expected on other pages (holds table, items detail page etc.). Sponsored-by: Koha-Suomi Oy Signed-off-by: David Nind Signed-off-by: Andrew Fuerste Henry Signed-off-by: Lucas Gass (cherry picked from commit 4e6e7bd914131ecdbb7f097f8696eb23e281be34) Signed-off-by: Jacob O'Mara Signed-off-by: Wainui Witika-Park --- koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc | 2 +- koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc | 2 +- .../intranet-tmpl/prog/en/modules/catalogue/results.tt | 6 +++--- .../intranet-tmpl/prog/en/modules/members/memberentrygen.tt | 4 ++-- .../intranet-tmpl/prog/en/modules/virtualshelves/shelves.tt | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc index f760ebc811..d34f74d6ec 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc @@ -271,7 +271,7 @@
  • Place hold
  • Place hold for [% INCLUDE 'patron-title.inc' patron => holdfor_patron no_title => 1 %]Place hold for [% INCLUDE 'patron-title.inc' patron => holdfor_patron no_title => 1 no_html => 1 %]
  • diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc index 7161ca7a3b..dbf7017349 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/patron-title.inc @@ -47,7 +47,7 @@ [%- SET display_patron_name = 0 -%] [%- END -%] [%- END -%] -[%- IF hide_patron_infos_if_needed AND ( display_patron_name OR display_cardnumber ) -%] +[%- IF !no_html AND (display_patron_name OR display_cardnumber) -%] [%- IF link_to == 'circulation_reserves' -%] [%- PROCESS display_patron_name -%] [%- ELSIF link_to == 'circulation_recalls' -%] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt index 42f5bdc693..6ac6764963 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt @@ -165,9 +165,9 @@