From 1bf4904dcd46879161ae87dd787e8ed9a8c03789 Mon Sep 17 00:00:00 2001 From: Casey Conlin <101153261+CaseyConlin@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:45:17 -0400 Subject: [PATCH] 16631 reports libraries (#1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bug 38928: Handle rft_id or id If a semicolon exists, the key should be what's before the semicolon, and its value, whats the after. Otherwise, default to 'doi' as it was before. To test: 1) Enable ILLModule. 2) Visit the following URLs http://localhost:8080/cgi-bin/koha/opac-illrequests.pl?op=create&backend=Standard&openurl=1&genre=article&id=10.1016/j.cognition.2024.105913 http://localhost:8080/cgi-bin/koha/opac-illrequests.pl?op=create&backend=Standard&openurl=1&genre=article&id=doi:10.1016/j.cognition.2024.105913 3) Notice that in both cases, only the doi value '10.1016/j.cognition.2024.105913' should be present in the input. Signed-off-by: Caroline Cyr La Rose Signed-off-by: Baptiste Wojtkowski Signed-off-by: Lucas Gass * Bug 38928: (QA follow-up) Signed-off-by: Lucas Gass * Bug 23010: Add system preference PreventWithdrawingItemsStatus To test: 1. APPLY PATCH, updatedatabase, and restart_all 2. Search for the system preference, PreventWithDrawingItemsStatus 3. Select both in transit and checked out, then save 4. Find an item and put it in transit. 5. Now from the item detail page, go to manage items > edit item 6. Using the item that was put in transit, attempt to change the status to withdrawn. 7. You should see an error at the top of the page 'In transit item cannot be withdrawn.' Make sure the item did not get marked as withdrawn. 8. Using a different item, do a checkout 9. Now from the item detail page, go to manage items > edit item 10. Using the checked out item, attempt to change the status to withdrawn. 11. vYou should see an error at the top of the page 'Onloan item cannot be withdrawn.' Make sure the item did not get marked as withdrawn. 12. Now, using the in transit item, go to the items tab. ( catalogue/moredetail.pl?biblionumber=x ) 13. Under Statuses, attempt to withdraw the item. 14. You should see an error near the top of the page "Cannot withdraw item in transit". 15. Now, using the checked out item, go to the items tab. ( catalogue/moredetail.pl?biblionumber=144 ) 16. Under Statuses, attempt to withdraw the item. 17. You should see an error near the top of the page "Cannot withdraw checked out item.". 18. Using both the in-transit and checked out item, attempt to modify the status through batchMod. 19. Ensure that the items are not being updated to withdrawn. 20. Turn off PreventWithDrawingItemsStatus system preferece. 21. Going through each of the steps again, except this time your items should successfully withdraw. prove t/db_dependent/Koha/Item.t Signed-off-by: Roman Dolny Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Add ability to block withdrawning of items with certain statuses Signed-off-by: Roman Dolny Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Handle error in updateitem.pl and template Signed-off-by: Roman Dolny Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Add unit tests Signed-off-by: Roman Dolny Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Fix file permission of atomicupdate Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Update pref name to PreventWithdrawingItemsStatus Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Report on count of items not modified via batchMod Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Handle error in C4/Items.pm using try/catch Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Add tests for AutomaticItemModificationByAge Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Remove JS added by mistake Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Clean up try/catch in additem.pl Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: More unit tests Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: (QA follow-up) a few trivial fixes - Update the dbrev to use say_success, and make dbrev and installer consistent - Change error div in moredetail.tt from info to warning Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 23010: Adjust tests Signed-off-by: Lucas Gass * Bug 23010: DBRev 25.06.00.001 Signed-off-by: Lucas Gass * Bug 39939: Cancel selected holds button on waitingreserves.pl is the same color as the background This patch makes some minor changes to the "Holds awaiting pickup" page so that the cancel buttons are clear and usable. The patch also wraps the reference to the TransferWhenCancelAllWaitingHolds system preference in a permission check so that it can be linked to the preference when appropriate. To test you should have some waiting holds in three categories: 1. Holds which have not been waiting longer than the number of days specified in the ReservesMaxPickUpDelay system preference. 2. Holds which have been waiting longer. I belive the only way to test this is to manually update the expiration date of an already waiting hold so that it is in the past. 3. Waiting holds which a patron has requested be cancelled. (Requires that the patron and hold are allowed according to the "Cancellation allowed" setting under Administration -> Circulation and fine rules -> Default waiting hold cancellation policy. - Log in to the OPAC as a patron who has a waiting hold. On the "Your summary" page, under the "Holds" tab, click the "Request to cancel" button for at least one of the waiting holds. - In the staff interface, go to Circulation -> Holds awaiting pickup. - Under each tab, check the appearance of the "Cancel selected" buttons (and the "Cancel and transfer all" button under "Holds awaiting past..." tab). - When testing as a user with system preference privileges, and the TransferWhenCancelAllWaitingHolds preference set to "Don't transfer," the hint shown under the "Holds awaiting past..." tab should be linked to system preferences. A user without system preference privileges should not see a link. Sponsored-by: Athens County Public Libraries Signed-off-by: David Nind Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 39939: (follow-up) Fix terminology - syspref to system preference Spell system preference in full, instead of syspref. Signed-off-by: David Nind Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 39206: Add an allowlist to Koha::CookieManager This patch adds a bit more control to what CookieManager does by adding a hardcoded allowlist of cookie names that are cleared at logout. Allowing at the same time to add entries to that list by using koha-conf lines or removing entries from the hardcoded list by using lines. The patch fixes the expiration of cookies that should be removed by passing max-age 0. Also it adds a theoretical path correction for always_show_holds but since we do not clear that cookie, it is currently unused. This seems to be the only Koha cookie where we use a longer path. Test plan: Run t/CookieManager.t Go to OPAC, login, select a few OPAC search results and send them to cart. This would create cookie bib_list. (Check dev tools.) Logout from OPAC and check cookie in your browser dev tools. What you see, depends on the browser. But the cookie should be either gone or empty and expired (FF: Session). Now add a line for bib_list in koha-conf. Restart all. Repeat search, add to cart. Logout. Check again in dev tools that bib_list is not empty, not expired. Check out an item. And click on 'Always show checkouts...' on the patron checkout form. This should create the cookie with value DO. Logout from intranet. Check that cookie was not affected. Now add a line for the following cookie: issues-table-load-immediately-circulation. Restart all. Login and logout from staff again. Check that cookie is empty and expired, or just gone. Bonus for devs: Create some custom cookie, and test keeping or removing it similar as above. Signed-off-by: Marcel de Rooy Signed-off-by: Paul Derscheid Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39206: Modify koha-conf templates Test plan: Just read the patch. Signed-off-by: Marcel de Rooy Signed-off-by: Paul Derscheid Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40242: Remove double operator in Quotes.pm Test plan: Read patch. Run t/db_dependent/Koha/Quotes.t Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 39912: Update RealTimeHoldsQueue when hold pickup location is updated When a hold's pickup location is changed we should rebuild the holds queue. To test: 1 - Enable RealTimeHoldsQueue 2 - Enable LocalHoldsPriority where pickup library matches home library 3 - Place two biblio level holds on a bib with one item for two different patrons for delivery to a different library then the home library 4 - Check the queue - firstpatron should have priority 5 - Change the pickup location for the second hold to be picked up at the home library 6 - Check the queue, unchanged 7 - Change the pickup location back 8 - Apply patch, restart all 9 - Change the pickup location to the items home library again 10 - Check the queue 11 - Second patron has now been given priority Signed-off-by: Michelle Spinney Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40022: Add the 25.11 release team This patch updates the teams.yaml to include the voted in 25.11 release team. Test plan 1/ Check against https://wiki.koha-community.org/wiki/Release_Teams Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass * Bug 40022: Add missing roles to the include This patch adds missing role mappings to the about-team.inc template to ensure all roles defined in teams.yaml are properly displayed. Added role mappings include: - manager_assistants (plural form) - maintainer_assistants (plural form) - maintainer_mentors (plural form) - accessibility_advocates (plural form) - security_manager - meeting_facilitator - social_media - website Also adds display logic for historical roles that may not be present in current teams but appear in contributor lists from teams.yaml. This ensures complete coverage of all team roles across historical and current release teams. Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass * Bug 40022: Condense display by hiding versions under ellipses This patch improves the contributor section display in the about page by implementing a condensed view for version lists. When a contributor has more than 2 versions for a role, only the first 2 are shown with an ellipsis (...) that can be hovered to reveal the remaining versions. The implementation: - Sorts versions in reverse chronological order (most recent first) - Shows first 2 versions directly - Hides additional versions under a hoverable ellipsis using Bootstrap tooltips - Adds CSS styling for the ellipsis with dotted underline and help cursor This makes the contributor lists more readable while preserving access to complete version information. Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass * Bug 40022: Sync teams in Koha, Wiki and release-tools Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass * Bug 40022: (QA follow-up) Tidy about-team.inc, about.tt Signed-off-by: Lucas Gass * Bug 40101: Unit tests Signed-off-by: Tomas Cohen Arazi Signed-off-by: Kristi Krueger Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40101: Add `Koha::Patron->can_place_holds()` This patch adds a new method to the `Koha::Patron` class. As described in the POD, this method makes checks on the patron's current situation and returns a boolean telling if it should be allowed to place holds. This doesn't check specific item/biblio holdability. It only covers patron specific conditions that could prevent holds to be placed. Both in `opac-reserve.pl` and `reserve/request.pl` this checks are all run, and all blocking situations are presented to the UI user. Feedback in community (so far) expressed this is a desirable situation, so that behavior can be retained with the use of the `no_short_circuit` parameter. If `no_short_circuit` is not passed, then the routine will return on the first blocking condition it finds. An `overrides` parameter is added, allowing to be passed a list of strings that match the possible error messages. This way, this method can be asked not to check for patron expiration, for example, and things like that. This is of course designed with the API overrides use case in mind. To test: 1. Apply this patches 2. Run: $ ktd --shell k$ prove t/db_dependent/Koha/Patron.t => SUCCESS: Tests pass! 3. Sign off :-D Signed-off-by: Tomas Cohen Arazi Signed-off-by: Kristi Krueger Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40101: Make opac-reserve.pl use `$patron->can_place_holds()` Signed-off-by: Tomas Cohen Arazi Signed-off-by: Kristi Krueger Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39951: Fix column filter offsets Test plan: 1) Enable ERM module 2) Create an agreement and a license with a vendor 3) The table filters will be out of sync - Agreements - only the vendor filter is incorrect, it sits above the name column instead of the vendor column - Licenses - all dropdown filter options will be left shifted by one 4) Apply patch 5) yarn js:build 6) Hard refresh the browser 7) All the filters should now be above the correct columns Signed-off-by: Roman Dolny Signed-off-by: Jonathan Druart Signed-off-by: Lucas Gass * Bug 39498: Correct patron restrictions displays This patch updates the way patron restrictions are displayed in the OPAC and staff interface, with the intention of making the details of each restriction more clear. In the OPAC, a new include file is created to be reused on the holds page and the user summary page. opac-user.pl is updated to allow a parameter to be passed to automatically open the "Overdues" tab. Test plan: 1. Before applying the patch, check how the display is currently. First set syspref PatronRestrictionTypes to "Allow" 2. Add two different new restriction types, fill out both "Code" and "Label" 3. Go to a patron's checkout page and add one of each of these restrictions, but do not fill out the comment field when adding them! 4. Observe that in the checkouts page and details page of the patron, it just says "Restricted since..." and does not show the restriction types. 5. Add another restriction, this time fill out the comment field 6. Observe that now in checkout and detail pages, the labels from the restriction types are listed and the comment shown. 7. Apply patch 8. Go to patron's details and checkout pages and check the restrictions are now displayed correctly, that is the text "with the explanation" is only shown for the restrictions that actually have a comment 8b. Log in to the OPAC with that patron and check they are displayed correctly in their summary page and when the patron is trying to place a hold. 9. Go to a different patron's account and add a restriction without a comment 10. Check it is now displayed correctly 11. Add more restrictions and check they are displayed correctly. Also add an OVERDUES restriction: 11a. Find a patron with an overdue item checked out (or create an overdue checkout on a patron's account) 11b. Go to Tools -> Overdue notice/status triggers 11c. Set up a rule for that patron's category, e.g. "First" -> Delay: 1, make sure to mark the check box for "Restrict" and "Print" 11d. Run misc/cronjobs/overdue_notices.pl 11e. That patron should now also have an OVERDUES restriction 12. Turn PatronRestrictionTypes off again and check the patrons if everything is still displayed correctly 13. Go to another different patron and add a restriction with no comment, check if it is displayed correctly 14. Add another restriction with a comment and check it is displayed correctly 15. Log in to the OPAC with the patron that had OVERDUES restriction and check they are displayed correctly in their summary page and when the patron is trying to place a hold. 16. Same thing for the other patron without the OVERDUES restriction. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39657: Unit tests Signed-off-by: Kristi Krueger Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39657: Spec changes Signed-off-by: Kristi Krueger Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39657: Add more checks and overrides to hold creation endpoint This patch adds new behaviors to the `POST /holds` endpoint. It uses the framework we created in the past for overriding policy rules, and add new options: * expired * debt_limit * bad_address * card_lost * restricted * hold_limit Some status codes are changed from 403 to 409. This should be revisited accross the codebase, as I think we made a wrong choice. Happy to review in this bug. The feature makes use of the newly introduced `$patron->can_place_holds()` method, which accepts to be passed through the overrides. To test: 1. Apply this patches 2. Run: $ ktd --shell k$ yarn api:bundle k$ koha-plack --restart kohadev k$ prove t/db_dependent/api/v1/holds.t => SUCCESS: Tests pass! 3. Test the endpoint with the various scenarios using your favourite REST tool (Postman!) 4. Sign off :-D Signed-off-by: Kristi Krueger Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40079: Add ul/ol and li to allowed tags in notes profile This patch add the unordered list, ordered list and list item html tags to the list of allowed tags in C4::Scrubber. Test plan: 1) Add a course reserve and include the following in the public note field:
  • First item
  • Second item
2) View the course details page and note "First item Second item" all appears on the same line (the ul and li tags have been stripped) 3) View the course reserves page and note the same issue in the public notes field of the table display 4) Apply this patch 5) Repeat 2 and 3 and note you now have a bullet pointed list displayed in both places 6) The display of the note on the details page may look mis-aligned.. that will be dealt with on it's own bug Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40079: (follow-up) Add dl, dt, dd tags to notes profile scrubber Adds support for HTML description list elements (dl, dt, dd) to the 'note' profile in the HTML scrubber configuration. This allows librarians to use description lists in note fields for better structured content presentation. Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40079: (follow-up) Update unit test Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40079: (follow-up) Improve test coverage and fix undef handling This patch modernizes the Scrubber.t unit test with comprehensive coverage following Koha best practices: - Uses subtest structure for logical grouping - Tests all scrubber types (default, comment, note) - Includes security testing for XSS prevention - Covers edge cases and error handling - Tests new list elements added in previous commits Also fixes C4::Scrubber to handle undef parameters cleanly by treating them as 'default' type instead of generating warnings. Test plan: 1. Run prove t/Scrubber.t 2. Verify all tests pass without warnings 3. Confirm comprehensive coverage of module functionality Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40254: Fix error in overrides check allowing too much This patch fixes a subtle (yet naive) error making the controller not care about blocking conditions if they were more than one and the first one was overridden. To test: 1. Apply the regression tests 2. Run: $ ktd --shell k$ prove t/db_dependent/api/v1/holds.t => FAIL: Tests fail! Some tests expect a 409 (denied for a conflict) but return a 201! 3. Apply this patch 4. Repeat 2 => SUCCESS: Tests pass! 5. Sign off :-D Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40254: Regression tests This patch makes the tests related to `can_place_holds` cover more use cases, and highlight an underlying issue in the controller. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40039: Add production enhancements to build-git-snapshot tool this patch adds some useful features to allow the build-git-snapshot tool to build production packages the patch adds the following options: --urgency, -u the urgency string for the resulting package. Default is '$urgency'. --incr, -i set debian revision (default = '-1') --(no)autochangelog whether or not to update the debian/changelog file. Default is to update it. note: this patch does not change any of the existing behaviour of the tool test plan to come... Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39534: Hide reports subgroup filter if there are no subgroups This patch updates the JavaScript which runs on the list of saved SQL reports, adding a check for report subgroups to the display of the report subgroups dropdown. The patch also hides the subgroups dropdown if there is no saved tab, in which case the tabsInit function doesn't run. To test you should have multiple reports organized in multiple groups and subgroups. See the test plan on Bug 39534. - Go to Reports -> Saved SQL reports. - If the page loads with the "All" tab active, there should be no subgroups dropdown. - If the page loads under a different tab, the subgroups dropdown should only show if that group has subgroups. - Switch between the various report group tabs to confirm that the subgroups dropdown is shown or hidden correctly based on the existence of subgroups. Sponsored-by: Athens County Public Libraries Signed-off-by: Anneli Österman Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 39954: Fix cataloging search results incorrect menu markup This patch corrects the dropdown menu markup in the "Records found in the reservoir" section of the cataloging search results page. It was not upgraded to Bootstrap 5 markup. To test, apply the patch and go to Cataloging. - Click "New from Z39.50/SRU" - Perform a search which will return multiple results. - Close the popup window and perform the same search in the "Cataloging search" header form. - Scroll down to the "Records found in the reservoir" section. - Click the "Actions" menu on one of the results. The menu should look correct. Sponsored-by: Athens County Public Libraries Signed-off-by: Roman Dolny Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 40250: Wrong link to NoIssuesChargeGuarantorWithGuarantees in patron category page This patch corrects the link to the NoIssuesChargeGuarantorsWithGuarantees system preference in the patron category creation/modification page. To test: 1. Apply patch 2. Go to Administration > Patron categories 3. Click 'New category' 4. Check that the hint under 'Guarantors with guarantees checkout charge limit' links to the correct system preference 5. Click on the link and make sure it links to the correct system preference Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40250: Terminology changes 'preference' to 'system preference' This patch corrects the terminology used in the patron category settings page, changing 'preference' to 'system preference'. https://wiki.koha-community.org/wiki/Terminology#P To test: 1. Apply patch 2. Go to Administration > Patron categories 3. Click 'New category' 4. Check that the hints under 'Checkout charge limit', 'Guarantees checkout charge limit', and 'Guarantors with guarantees checkout charge limit' use 'system preference' and not 'preference' Signed-off-by: Owen Leonard Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40244: Fix typo in branchoverdues.tt This patch fixes a trivial typo. The text appears in two more places with the right form on the same template. Signed-off-by: Tomas Cohen Arazi Signed-off-by: Owen Leonard Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 39871: Don't pass undef for non-nullable fields from batch mod tool To test: 1. Set not-for-loan, withdrawn, and damaged statuses on some items 2. Try to edit only those items with the Batch item modification tool 3. Check the checkboxes to clear the withdrawn, not-for-loan, and damaged statuses 4. Click Save 5. View the background job report --> Note that it says the items could not be modified 6. Look at the items --> The statuses have not been cleared 7. Apply patch and restart_all 8. Repeat steps 2-5 --> The background job report says the modifications were successful 9. View the items --> The statuses have been cleared Signed-off-by: David Flater Signed-off-by: Owen Leonard Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 39871: (QA follow-up) Do not hardcode nullable check Lets check DBIx's columns_info. Test plan: Try to blank an integer column and a string column. Verify results. Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 34776: Restore patron messaging preferences if error occurs during new account creation If error occurs while creating a new patron messaging preferences are either lost or reseted as default fro patron category. This patch adds new method restore_form_values to restore already added messaging preferences. To test: 1. Enable syspref EnhancedMessagingPreferences. 2. Create a new patron but cause an error to prevent it from saving (e.g. add wrong age). 3. Add messaging preferences for patron (if there are default preferences, add also new ones or remove defaults). 4. Attempt to save. => Note that messaging preferences were lost and you need to readd them. 5. Apply this patch. 6. Repeat steps from 2 to 4. => Note that messaging preferences which you added are kept even if error occurs. Sponsored-by: Koha-Suomi Oy Signed-off-by: Jesse Maseto Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 34776: Unit tests Just a small beginning.. Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 34776: Remove unneeded if statement We don't need to check if $op is add_form after error, since this value always changes. Sponsored-by: Koha-Suomi Oy Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 34776: Add unit tests for sub restore_form_values Test that input values don't change when send to the sub restore_form_values. To test prove t/Form_MessagingPreferences.t Sponsored-by: Koha-Suomi Oy Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40030: Escape values when displaying action logs comparison When viewing the action logs for a system preference change, there is an option to view a comparison between different log lines for the same system preference. However, if a system preference value contains HTML markup (e.g. in IntranetUserJS), the diff text is only escaped on sections where a change is marked, so unchanged lines containing HTML markup result in the HTML being rendered. Escape the string values for unchanged sections as well, to ensure that HTML markup in the diff text will not be rendered. To test: 1. Edit IntranetUserJS and add some code that contains HTML markup. For example: $("body").append('Say hi'); 2. Save the preference 3. Make another change to IntranetUserJS that does not affect the line you just added, and save again to ensure there are at least 2 action log lines for comparison 4. Go to Tools > Log viewer 5. Select System Preferences module and Submit 6. Find the log entries for the above two revisions to IntranetUserJS 7. Check the Compare checkboxes on those entries, and click View comparison --> Note that the HTML button is rendered in the comparison 8. Apply patch 9. Clear browser cache and refresh the page 10. Repeat step 7 --> The button is not rendered and the code is displayed as written 11. Make a change to the line you added in step 1 (for example, replace "Say hi" with "Say hello") 12. Refresh the page 13. Check the checkboxes for the newest 2 log entries and click View comparison to view the diff for that last change --> Confirm the change is shown correctly - the button is not rendered and nothing has been double-escaped Signed-off-by: Phil Ringnalda Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40249: "Copy settings" should be "Copy permissions" This patch changes the "Copy sesttings" button on the patron permissions page to return it to its previous text "Copy permissions." This is consistent with related controls on the page. To test, apply the patch and locate a patron in the staff interface. From their checkout or detail page choose More -> Set permissions from the toolbar. In the toolbar of permissions-related controls you should see a button labeled "Copy permissions." Sponsored-by: Athens County Public Libraries Signed-off-by: David Flater Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40164: Add Template::Plugin::JSON dependency Signed-off-by: Tomas Cohen Arazi Signed-off-by: David Cook Signed-off-by: Lucas Gass * Bug 31632: Link a suggestion to an existing order This enhancement allows library staff to link an order (in an unclosed basket, or a standing order) to an accepted suggestion. To test: 1) In the staff interface, go to Suggestions and create at least two suggestions. 2) Mark at least two suggestions as Accepted. 3) Go to Acquisitions, create a vendor if you don't have one already. 4) Have or create two baskets - one should be standing, and one not standing (normal). 5) In the normal basket (not standing), add an order from any source but NOT from a suggestion. 6) When you save the order, there should be a new link in the Modify column of the Orders table - "Search for suggestion to link". Click this. 7) Choose one of your suggestions to link to the order. 8) You should be redirected back to the basket. Confirm your order has been correctly linked to the suggestion. Confirm there is no link to "Search for suggestion to link" for this order now that a suggestion has already been linked. 9) Add another order to this basket from any source but NOT from a suggestion. 10) Close the basket. Confirm there is no link to "Search for suggestion to link" because the basket is closed, but you could reopen the basket to link the order if you wanted to. 11) Go to Baskets in the left navigation so you can find your standing basket. 12) Add an order to your standing basket from any source but NOT from a suggestion. 13) Go to the vendor and Receive shipments. Receive your standing order and finish receiving. 14) Go to the standing basket. There should be a new unreceived standing order for the record you just received, with a link to "Search for suggestion to link". Click this. 15) Choose a suggestion to link to the order. 16) You should be redirected back to the basket. Confirm your orders for this record have been correctly linked to the suggestion. Sponsored-by: Pymble Ladies' College Signed-off-by: Tomas Cohen Arazi Signed-off-by: Andrew Fuerste Henry Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 31632: (follow-up) Simplify link text Signed-off-by: Tomas Cohen Arazi Signed-off-by: Andrew Fuerste Henry Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 31632: (follow-up) CSRF protection for linking order to suggestion Signed-off-by: Andrew Fuerste Henry Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 31632: (QA follow-up) Adjust TT filters and remove extra form-submit.js Signed-off-by: Emily Lamancusa Signed-off-by: Aleisha Amohia Signed-off-by: Lucas Gass * Bug 31632: (QA follow-up) Align behavior with order from suggestion If an order is added from a suggestion in the first place, the suggestion automatically changes status to ORDERED, and a notice is sent out to the patron. If a suggestion is linked to the order after the fact, it should move to ORDERED and notify the patron as well. Signed-off-by: Emily Lamancusa Signed-off-by: Aleisha Amohia Signed-off-by: Lucas Gass * Bug 33729: Added date accessioned to items search table Test plan: 1. Apply patch 2. Go to item search 1. Notice that there is now a date accessioned column 2. Export the table into a CSV and notice that there is also a date accessioned column there 3. Sign off and have an amazing day :D Signed-off-by: Emmanuel Bétemps Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 33729: Added dateaccessioned to column_settings.yml Signed-off-by: Andrew Auld Signed-off-by: Emmanuel Bétemps Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 33729: Added datacolumn for date accessioned Signed-off-by: Emmanuel Bétemps Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 33729: (QA follow-up) Tidy Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 38939: Add reservenote column to members/holdshistory.pl To test: 1. APPLY PATCH, restart_all 2. Make some holds for patrons in both the staff client and the OPAC. ( For OPAC turn on OpacHoldNotes ) 3. Make sure you add some notes to each of these holds. 4. Go to the patron account and click on the 'Holds history' tab. 5. Make sure the hold note is there and looks correct. 6. Ensure you can hide the coluimn properly via Table settings. Signed-off-by: Andrew Auld Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39441: Some staff interface templates have div.container instead of div.container-fluid This patch updates a few templates so that div.container is replaced with div.container-fluid. div.container gives us a fixed maximum width that isn't consistent the rest of Koha. To test, apply the patch and go to the staff interface. - Perform a catalog search which will return multiple results. - In the search results, check multiple results and click "Add to cart." - Click the cart icon in the top menu to trigger the cart popup. - The contents of the cart popup should fill the whole width of the window. - The other instances of this are less noticeable because of how the pages work. These changes are more about consistency: - The OPAC place hold page - The club enrollment process (both in the OPAC and the staff interface) - As long as these interactions work correctly all is good. Sponsored-by: Athens County Public Libraries Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 40281: Hide the type column on the patron circulation history page This fixes the patron circulation history page so that the type column is hidden. The type column on a patron's circulation history page was hidden by Bug 38954 - Hide checkout type using colvis. However, the commit for Bug 37273 - Add ID column to Agreements table in the ERM, inadvertently reversed hiding the column. Test plan: 1. Check out an item to a patron (for example, 39999000011418 to Mary Burton). 2. Look at the patron's circulation history page (Patrons > Mary Burton > Circulation history), and note there is a 'Type' column shown with a value of 'standard_checkout'. 3. Note that you can't hide the column, from either selecting the 'Columns' or 'Configure' options for the table. 4. Apply the patch, restart everything (restart_all), and clear your browser cache. 5. Repeat step 2. Note that there is now no 'Type' column shown and it is not configurable, from either selecting the 'Columns' or 'Configure' options for the table. Signed-off-by: David Nind Signed-off-by: Laura_Escamilla Signed-off-by: Lucas Gass * Bug 34561: Move IntranetReportsHomeHTML to HTML customizations This patch moves the IntranetReportsHomeHTML system preference into HTML customizations, making it possible to have language- and library-specific content. To test you should have some content in the IntranetReportsHomeHTML system preference before applying the patch. Apply the patch and run the database update process. - In the staff client, go to Tools -> HTML customizations and verify that the content from IntranetReportsHomeHTML is now stored there. - The HTML customization entry form should offer IntranetReportsHomeHTML as a choice under "Display location." - Update and reinstall active translations (for instance fr-FR): - perl misc/translator/translate update fr-FR - perl misc/translator/translate install fr-FR - Enable the translation if necessary under Administration -> System preferences -> language. - Edit the IntranetReportsHomeHTML HTML customization and add unique content to the "fr-FR" tab. - Go to the reports home page. You should see the content you added to the IntranetReportsHomeHTML HTML customization. - Switch to your updated translation and confirm that the content you added for your translation shows up correctly. - Go to Administration -> System preferences and search for "IntranetReportsHomeHTML." It should return no results. Sponsored-by: Athens County Public Libraries Signed-off-by: Ray Delahunty Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 34561: (QA follow-up) Rename to StaffReportsHome to match othe html customizations I noticed the rest of the html customizations don't have html in the option name, so I renamed for consistency. Signed-off-by: Lucas Gass * Bug 34561: DBRev 25.06.00.002 Signed-off-by: Lucas Gass * Revert "Bug 40164: Add Template::Plugin::JSON dependency" This reverts commit d3783f8859cbcdd3dce01f37c41bf47981200eea. Signed-off-by: Lucas Gass * reports_branches table SQL established * Make DBversion in sync with the Koha module * Add Filter Reports system preference. Add UI for managing reports. * Add ReportsBranch.pm * Not working. Trying to get branches to show up in guided_reports_start.tt. * Bug 40261: Tidy debian/build-git-snapshot Signed-off-by: David Flater Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 20601: Untranslatable strings in circulation statistics This patch makes some updates to the circulation statistics wizard in order to make more information translatable. The patch also adds some template plugins to the output of filter options in order to be able to show descriptions instead of codes, and corrects the markup for the 'Patron library' dropdown which wasn't working. To test apply the patch and go to Reports -> Statistics wizards -> Circulation. - Test setting some or all options in the "Filter column" and running the report. - Confirm that the "Patron library" dropdown works. - At the top of the results there should be a list of the filter options you selected and their values. - All the filter labels should be correct, and the filter values should should be in their full/description form rather than in code form (e.g. library, item type, collection code, sorting field, etc.) Sponsored-by: Athens County Public Libraries Signed-off-by: David Nind Signed-off-by: Aleisha Amohia Signed-off-by: Lucas Gass * Bug 37305: Subfield order matters This patch updates the use of a hash to store and then pass subfields to the MARC::Field new method to an array with key/value pairs using fat comma's. This allows us to maintain the integrity check that we're passing string as the first arguament in each pair whilst also allowing us to ensure fields are passed in the order they are found. Sponsored-by: Open Fifth Signed-off-by: Heather Hernandez Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 37305: Remove C4::Biblio::prepare_host_field This patch updates the only use of prepare_host_field to use the well tested Koha::Biblio->generate_marc_host_field method instead and then removes the aforementioned prepare_host_field method from C4::Biblio. Test plan 1) Ensure the "enhanced workflow" for creating analytics still functions as expected. Sponsored-by: Open Fifth Signed-off-by: Heather Hernandez Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 37305: (follow-up) Only add control number subfield when defined The previous commit introduced a bug where the control number subfield 'w' was being added to the MARC field even when undefined, causing test failures. This patch adds a condition to only push the control number subfield when the value is actually defined, matching the pattern used for other subfields in the method. Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40046: (bug 39606 follow-up) Remove waits and screenshots From bug 39606: """ Why are you taking screenshots? The wait statements will certainly cause random failures. cy.wait(5000); cy.wait(2000); Notice the following couple of lines: cy.get("#fileuploadstatus").contains("100%"); cy.get("legend").contains("Look for existing records in catalog?").should('be.visible'); It makes Cypress wait 10s until "100%" appears (ie. the file is updated), then the block with the dropdown lists you are going to interact with to be visible. You should almost never use cy.wait. """ Test plan: yarn cypress run --spec t/cypress/integration/Tools/ManageMarcImport_spec.ts should still pass Signed-off-by: David Nind Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass * Bug 40046: Prevent random failures when verifying select's values Commands like .select() are queued. We need to prevent the should to happen before the select is executed. Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass * Bug 40046: Use xml and auto-select it Absolutely no idea why the previous code was not selecting MARCXML (MARC was passed and so the import failed) cy.get('select[name="format"]') .select("MARCXML", { force: true }) .should("have.value", "MARCXML"); But I found a bug in the JS code: we are supposed to auto-detect .xml file and pre-select MARCXML. So let's rely on that behaviour! sample.mrc is actually an xml file so it makes sense to rename it Signed-off-by: Paul Derscheid Signed-off-by: Lucas Gass * Bug 39289: Display all checkouts in the batch extend due date tools When paginate is false, pageLength is still used. If more than 20 checkouts should be displayed, only 20 will. Test plan: Have more than 20 checkouts, use the batch extend due date tool and notice that all checkouts are displayed when this patch is applied. Signed-off-by: Magnus Enger Tested on top of bug 39081. Signed-off-by: Baptiste Wojtkowski Signed-off-by: Lucas Gass * Bug 40277: Remove warn in C4::Koha::GetAuthorisedValues() When using the OPAC and you are not logged in, there are warnings in the logs: [WARN] Use of uninitialized value $branch_limit in concatenation (.) or string It comes from C4::Koha::GetAuthorisedValues() : my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : ""; my $cache_key = "AuthorisedValues-$category-$opac-$branch_limit"; C4::Context->userenv->{"branch"} can be undef The patch fixes using C4::Context::mybranch(). Test plan: 1. Set the OpacAdvancedSearchTypes system preference to something other than "itemtypes", for example "loc". 2. Go to OPAC without logging in, and perform a search. 3. Check the /var/log/koha/kohadev/plack-opac-error.log and note the warnings in the log: [WARN] Use of uninitialized value $branch_limit in concatenation (.) or ... (Alternative, tail the logs: tail -f /var/log/koha/kohadev/*.log 4. Apply the patch. 5. Repeat step 2 and check that there are no longer any warnings. 6. Sign off. Signed-off-by: David Nind Signed-off-by: Jonathan Druart Signed-off-by: Lucas Gass * Bug 40277: Add a test Signed-off-by: Jonathan Druart Signed-off-by: Lucas Gass * Bug 40129: Fix selenium tests Signed-off-by: Lucas Gass * Bug 38899: Fix Cypress tests Signed-off-by: Lucas Gass * Bug 40164: Add Template::Plugin::JSON dependency Signed-off-by: Tomas Cohen Arazi Signed-off-by: David Cook Signed-off-by: Lucas Gass * Bug 40164: (follow-up) Update debian/control Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39876: Move `git ls-files` to Koha::Devel::Files This patch introduces a new Koha::Devel namespace. It clearly shows that its purpose is for development and will not contain any business logic. Signed-off-by: David Nind Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39876: Add context for tidy With this patch we adjust what's needed to make misc/devel/tidy.pl run identically as before Signed-off-by: David Nind Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39876: Apply module to other tests We are ready to reuse Koha::Devel::Files in other places where `git ls-files` is used. Signed-off-by: David Nind Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39876: Get TT files for tt_tidy Signed-off-by: David Nind Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39876: Make find-missing-op-in-forms.t test TT files Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39876: Add build-git-snapshot type resolution Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 39876: Make build-git-snapshot pass codespell Signed-off-by: Lucas Gass * Bug 40168: Restore afterEach in KohaTable Cypress tests We defined an anonymous function inside an arrow function, and Cypress does not call it. Test plan: Set AlwaysShowHoldingsTableFilters to "Do not" Run t/cypress/integration/KohaTable/Holdings_spec.ts: yarn cypress run --spec t/cypress/integration/KohaTable/Holdings_spec.ts When done, have a look at the value of AlwaysShowHoldingsTableFilters => without this patch it has been modified (not restored) and is set to "Do" => With this patch applied the original value is restored at the end of the tests (actually the end of each test) Signed-off-by: David Nind Signed-off-by: Pedro Amorim Signed-off-by: Lucas Gass * Bug 40168: Remove cleanup() call from afterEach Signed-off-by: David Nind Signed-off-by: Pedro Amorim Signed-off-by: Lucas Gass * Bug 40170: Replace cypress-mysql with mysql2 - Cypress tests This patch suggests to replace cypress-mysql with mysql2 cypress-mysql provides a custom Cypress command (cy.query) that run within the browser context. This approach mixes test-side and server-side and is limited in flexibility and error handling. mysql2 runs inside Cypress plugins (Node process) via cy.task calls, which are executed server-side (outside the browser) This is needed for the follow-up bug reports where we need to request the DB from other plugins Test plan: Run `yarn install` to install the mysql2 All the Cypress tests modified by this patch must still pass The new test t/cypress/integration/t/db.ts must also pass Signed-off-by: David Nind Signed-off-by: Pedro Amorim Signed-off-by: Lucas Gass * Bug 40316: Remove warnings from selenium/regressions.t Wide character in print at /usr/share/perl/5.36/Test2/Formatter/TAP.pm line 156. Test plan: Confirm that % prove t/db_dependent/selenium/regressions.t still passes and does not generate warnings Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40317: Remove warnings from Auth_with_shibboleth.t output t/db_dependent/Auth_with_shibboleth.t .. 1/5 GetPreparedLetter called at t/db_dependent/Auth_with_shibboleth.t line 73. EnqueueLetter called at t/db_dependent/Auth_with_shibboleth.t line 80. SendQueuedMessages called with message_id: 42 at t/db_dependent/Auth_with_shibboleth.t line 90. Not sure what exactly is going on here, but warnings_are is not supposed to show the warnings in the output. I think it's because of the logger mock. A workaround is to use a variable we increment then compare to see if we reach the sub. Test plan: % prove t/db_dependent/Auth_with_shibboleth.t should return green without warnings Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39448: Layout improvement for search filter administration This patch makes a few minor changes to the search filter administration template. To test, apply the patch and rebuild the staff interface CSS. - If the SavedSearchFilters system preference is not enabled, go to Administration -> System preferences and enable it. - Perform a catalog search. - From the search results page, click "Save as search filter" at the top of the results. - Save your filter. - Go to Administration -> Search filters. - The table of filters should be wrapped in a "page-section" div with the heading above it. - In the "Actions" column the buttons should be aligned in a row with space between each. - Click "Edit filter" - In the modal the form fields should be well laid out. Sponsored-by: Athens County Public Libraries Signed-off-by: Felicie Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 40176: Add tests This patch adds a new subtest to xt/api.t It ensures that maxLength will appear in the rest api spec file when there is a size constraint at the DB level Signed-off-by: David Nind Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40176: Add maxLength to item spec file Test plan: Apply the "tests" patch first prove xt/api.t => fail Apply this patch => pass Signed-off-by: David Nind Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40177: Adjust tests Signed-off-by: David Nind Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40177: Add maxLength to library spec file Test plan: Apply the "tests" patch first prove xt/api.t => fail Apply this patch => pass Signed-off-by: David Nind Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40178: Adjust tests Signed-off-by: David Nind Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40178: Add maxLength to patron spec file Test plan: Apply the "tests" patch first prove xt/api.t => fail Apply this patch => pass Signed-off-by: David Nind Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40179: Adjust tests Signed-off-by: David Nind Signed-off-by: Lucas Gass * Bug 40179: Add maxLength to patron_category spec file Test plan: Apply the "tests" patch first prove xt/api.t => fail Apply this patch => pass Signed-off-by: David Nind Signed-off-by: Lucas Gass * The reports list can be limited by library via the query. * Add branch libraries to reports edit view. * Revert "Bug 36586: Define self-checkin timer using Javascript class" This reverts commit ff403dcfb3e2972597a49b447f4d55c208f13f4d. Signed-off-by: Lucas Gass * Bug 40170: Update yarn.lock Signed-off-by: Lucas Gass * Bug 40337: Define checkprevcheckout as ENUM On bug 40178 and bug 40179 we defined checkprevcheckout attributes as ENUM at the REST API level, so the specs prevent us from inserting values that are no yes, no, inherit in DB. However the DB schema didn't have that constraint. This has been caught by some tests that were failing: eg. t/db_dependent/selenium/patrons_search.t with "Not in enum list: yes, no, inherit." Test plan: Apply this patch, run `updatedatabase`, `dbic` and `restart_all` `prove t/db_dependent/selenium/patrons_search.t` should now pass. Signed-off-by: Lucas Gass * Bug 40337: DBIC schema changes Signed-off-by: Eric Garcia Signed-off-by: Lucas Gass * Bug 40337: DBRev 25.06.00.003 Signed-off-by: Lucas Gass * Bug 40337: Handle enum in Koha::Patron->anonymize We need to reset to the default value. We might have a problem (later) if it's NOT NULL and no default is set, which is not handled by this patch. But the situation does not seem to exist yet anyway. Signed-off-by: Lucas Gass * Bug 40337: Do not set checkprevcheckout to an empty string when importing patrons We must remove it so that it will be set as the default value defined at the DBMS level Signed-off-by: Lucas Gass * Bug 40319: Fix spacing in address display include This patch makes some spacing changes to the address display include in order to prevent address parts (e.g. city, state, zip, etc) from missing spaces in between. To test, apply the patch and locate or edit a patron record to include data in all main address fields. - Check out to the patron and check the display of the address in the sidebar. Confirm that the spacing is correct. - Test with all variations of the AddressFormat system preference. - Test with and without the use of road types (Administration -> Authorized values -> ROADTYPE) and street numbers. Sponsored-by: Athens County Public Libraries Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40165: Incomplete logic for controlling display of OPAC language footer This patch adds some additional logic to the template which controls the appearance of the footer in the OPAC. Some additional checks are required to make sure an empty footer doesn't display in some circumstances. To test, apply the patch and install at least one additional translation besides English. Check any OPAC page when various combinations of system preferences are enabled: - opaclanguagesdisplay - OPACLanguages - OpacLangSelectorMode - OPACReportProblem - CookieConsent - OpacKohaUurl In particular, confirm that there is not an empty footer when opaclanguagesdisplay is enabled but there is only one translation enabled. Sponsored-by: Athens County Public Libraries Signed-off-by: Roman Dolny Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40111: Fix title sorting on two reports This patch modifies two reports in order to correct sorting on title columns. To test, apply the patch and got to reports -> Lost items. - Run the report with parameters that will return multiple results. - Test sorting the title column. The articles 'a', 'an', and 'the' should be ignored. - Perform the same test with the "Orders by fund" report. Sponsored-by: Athens County Public Libraries Signed-off-by: Anneli Österman Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40092: Fill auto-populated control fields in MARC editors Problem: Clicking Save doesn't fill control fields automatically in both the authority and bibliographic MARC editors. Regression introduced when class `framework_plugin` was added: `AreMandatoriesNotOk()` rewrites the element `class` attribute with a hard‑coded string, dropping existing classes. Because the plugins that populate 000/003/005/008 rely on `framework_plugin`, the inputs are skipped and the fields remain empty. This patch stops clobbering the attribute and instead appends the visual 'notFilled' class via `elt.classList.add()`. The one-line fix is applied in both `authorities.tt` and `addbiblio.tt`. Test plan: Authority editor 1. Authorities → New authority → choose framework (e.g. Topical term). 2. Leave all fields blank, click Save. Before patch: 000, 003, 008 remain blank; required tags turn yellow. 3. Apply patch, hard‑refresh, repeat steps 1–2. After patch: control fields auto‑populate as in 24.11. Bibliographic editor 1. Cataloguing → New record (Not in Advanced MARC editor). 2. Click Save without entering data. Before patch: control fields stay blank; record cannot be saved. 3. Apply patch, hard‑refresh, repeat. After patch: record is blocked, but 000/005/008 auto‑populate. Both editors behave like 24.11; mandatory highlighting still works. Signed-off-by: David Nind Signed-off-by: Aleisha Amohia Signed-off-by: Lucas Gass * Bug 32934: Unit tests Signed-off-by: Lucas Gass * Bug 32934: Correctly honor the no block due date for SIP checkout messages **Problem:** When using SIP checkout messages with the "no block" flag, the specified due date was being ignored. Instead of honoring the provided due date, the system would: 1. Use the due date as the transaction timestamp (incorrect behavior) 2. Calculate a new due date based on circulation rules 3. Return an empty due date field (AH) in the SIP response This affected SIP2 integrations where external systems needed to specify exact due dates for checkouts, particularly for offline circulation scenarios. **Root Cause:** The `ProcessOfflineIssue` function in C4::Circulation was only returning a success/failure message, but the SIP checkout transaction needed access to the resulting checkout object to properly set the due date. The SIP Transaction::Checkout module was calling `ProcessOfflineIssue` but couldn't retrieve the checkout details to populate the transaction's due date field. **Solution:** 1. Modified `ProcessOfflineIssue` to return both the status message AND the checkout object: `return ( "Success.", $checkout );` 2. Updated `ProcessOfflineOperation` to handle the new return format by capturing only the message: `( $report ) = ProcessOfflineIssue( $operation );` 3. Modified SIP Transaction::Checkout to capture both return values and use the checkout object to set the proper due date via `duedatefromissue` 4. Fixed the timestamp parameter to use `dt_from_string` instead of the due date **Test Plan:** 1. **Unit Tests:** - Run `prove t/db_dependent/Circulation/OfflineCirculation.t` to verify ProcessOfflineIssue returns checkout object and respects due_date parameter - Run `prove t/db_dependent/SIP/Transaction.t` to verify SIP checkout honors no_block_due_date parameter 2. **Manual SIP Testing:** - Connect to SIP server via telnet on port 6001 - Send checkout message with no block flag and specific due date: `111YN20250115 18000120241201 180001AP|AO|AC|AD|AB|AA|` - Verify response contains correct due date in AH field - Verify checkout record in database has the specified due date 3. **Regression Testing:** - Verify normal SIP checkouts (without no block) still work correctly - Verify offline circulation operations continue to function - Verify ProcessOfflineOperation still processes queued operations correctly Signed-off-by: Brendan Lawlor Signed-off-by: Kyle M Hall Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40160: Use HTTPS for links to community websites Some web-browsers now only allow HTTPS, we should change links in templates with SSL : https://schema.koha-community.org, https://wiki.koha-community.org ... Test plan : Just look patch to check http > https Signed-off-by: Owen Leonard Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40088: Do not show edit button for default framework In Administration > MARC bibliographic frameworks > "MARC structure": Do not show "Edit framework" button in tools bar since one can not edit the default framework description. Currently it leads to new framework creation. Test plan : 1) Go to Administration > MARC bibliographic frameworks 2) On default framework row, click Actions > MARC structure 3) Check you dont see in tool bar "Edit framework" button 4) Go to Administration > MARC bibliographic frameworks 5) On a framework row (not default one), click Actions > MARC structure 6) Check you see in tool bar "Edit framework" button Signed-off-by: Owen Leonard Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 39572: Improve EDIFACT order confirmation message Add EAN account information to EDIFACT order confirmation message when the BasketConfirmations system preference is enabled. To test: 1. Set EDIFACT system preference to Enable 2. Set BasketConfirmations system preference to Enable 3. Create at least 2 EANs, one with a description and one without a description i. Go to Acquisitions > Library EANs ii. Click "New EAN" and fill in the fields 4. Create an EDI account i. Go to Acquisitions > EDI accounts ii. Click "New account" iii. Click Submit (for testing purposes you don't need to fill in the fields) 5. Find or create a basket for the same vendor that's on the EDI account 6. Add an order to the basket from any source 7. In the menu bar at the top of the basket screen, click "Create EDIFACT order" and select an EAN --> Note that the confirmation page doesn't tell you which EAN was selected 8. Click "No, don't close" 9. Apply patch and restart_all 10. Repeat step 7 --> The confirmation page should now display both the basket and the selected EAN 11. Click "Cancel" --> Confirm that the basket is still open 12. Repeat step 7 13. Click "Yes, generate order and close basket" --> Confirm the basket is closed 14. Click "EDIFACT messages" in the sidebar menu --> Confirm that you see a message with type ORDERS for that basket Signed-off-by: David Nind Signed-off-by: Kyle M Hall Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40332: Show tools sidebar category for batch extend due dates permission To test: 1 - have or create a user with the permissions batch_extend_due_dates edit_quotes but no other Tools 2 - log into koha as that user, go to Tools module, confirm both Batch Extend Due Dates and Quote Editor are available from the Tools module home page 3 - Click into either available tool, confirm the sidebar menu contains the category Additional Tools and a link to Quote Editor, but nothing else 4 - add the edit_notices permission to your user 5 - reload your page from step 3, confirm the sidebar menu now also contains the Patrons & Circulation category with both Notices & Slips and Batch Extend Due Dates. 6 - apply patch, restart services, reload page, confirm nothing has changed 7 - remove the edit_notices permission from your user 8 - reload your page from step 3, confirm the sidebar menu now contains the Patrons & Circulation category with only Batch Extend Due Dates. Signed-off-by: David Flater Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 40330: Conform and add labels to the OPAC Test plan: Enable the system preference: marcflavour: choose UNIMAR, PrivacyPolicyConsent, ILLModule, TagsEnabled, OpacCloud. 1- Apply the patch 2- Go to the OPAC, log in to a patron account. Go to personal details, check the html code of the date of birth field, and notice that there is a aria-hidden="false". 3- Inspect the search bar, and notice in the library select, there is a label with a for attribute which match the id. 4- Search a record, click on "save to list" and check the Category select, inspect if the label has a for attribute and match the select id. 5- Go to interlibrary Loan Request in the user menu, Check if the "Note" field has a label for attribute which match the id. 6- Go to Consent, check if the checkbox has a label for "Yes" and "No". 7- Go to Suggestions and check that the checkbox has the same id as the label in the Summary column. 8- Go to "Tag Cloud", inspect the HTML code of the "Tags to show from other users" label, notice that there is a for attribute which match the id of the input tag. and check if in the html code there is an aria-label with the term of the tag. 9- Go to Subject Cloud, check the html code, and notice that there is a label that surounds the input tag. 10- Go to Advanced Search, click on "More options", and check that all the additional options have a label with a for attribute which match the id of the select. Signed-off-by: Owen Leonard Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 39545: Better generation of 773 field for a child record (MARC21) When creating a child record (New > New child record from Normal view) the information put in field 773 is very basic, sometimes not complete (e.g. only one ISBN, only 245 $a in 773 $t, 773 $w missing 003 of the host record etc.) and put in random order. Test plan: ========== 1. Find any record to be a host record for an analytical record. You can enrich the record with multiple 020, 490+830 fields, make sure that there are 001 and 003 fields present. 2. From upper menu chose New > New child record. 3. See the generated field 773 - the subfields are incomplete and in random order. 4. Apply the patch ; restart_all. 5. Repeat p. 2.-3. See that the generated 773 field contains now much more information, including 773 $7 and also preset leader. Signed-off-by: Roman Dolny Rebased-by: Martin Renvoize The rebase removed the majority of this patch as the prepare_host_field method was removed entirely upstream. The follow-up patch re-implements the same but in the newer Koha::Biblio->generate_marc_host_field method instead. We also dropped the Unit tests that were introduced in the subsequent patch. Sponsored-by: Open Fifth Signed-off-by: Heather Hernandez Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39545: (follow-up) Apply same logic to Koha::Biblio This patch updates the Koha::Biblio->generate_marc_host_field method to more closely match the updated logic in C4::Biblio::prep_marc_host. We change a number of things including: 1) Constructinging the 773 subfield generation from a hash to an array to preserve field order. 2) Updating main entry handling for 100/110/111 fields to clone the field and then remove relevant subfields as apposed to fetching only a limited set of subfields. 3) Add handling to generate subfield 7 content depending on LDR and Main Entry information 4) Improve handling for title subfield construction from 245 to respect non-filing characters and remove trailing punctuation 5) Remove trailing punctuation from subfield b when generated from 250 6) Remove generation of subfield s from the 240 field entirely 7) Remove trailing punctuation from subfield d when generated from 260 8) Add generation of subfield k from 800-830 fields Rebased-by: Martin Renvoize We dropped the upstream aforementioned C4::Biblio method, but this patch faithfully replicates it's functionality within Koha::Biblio->generate_marc_host_field Sponsored-by: Open Fifth Signed-off-by: Heather Hernandez Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39545: (QA follow-up) Restore 240 field processing for subfield s This patch restores the generation of subfield s from field 240 (Uniform Title) in the MARC21 773 field generation, addressing cataloger feedback about the critical importance of this field for: - Bibles and books of the Bible - Laws and statutes - Translations - Academic and specialized library materials - Legal materials and treaties The MARC21 standard defines subfield s as "Uniform title (NR)" and this data is essential for proper bibliographic relationships. This patch also fixes a warning when 245 indicator 2 contains non-numeric values by adding proper validation. Test plan: 1. Create a record with a 240 field containing uniform title data 2. Generate a child record from it 3. Verify the 773 field now contains subfield s with the uniform title 4. Run prove t/db_dependent/Koha/Biblio.t to ensure all tests pass Sponsored-by: Open Fifth Signed-off-by: Heather Hernandez Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 39881: Add patron card number to transfers to receive table To test: 0. APPLY PATCH 1. Transfer an item from Library A to Library B 2. Place and item-level hold on the item 3. Set library to Library B 4. Go to Circulation > Transfers to receive 5. In the 'On hold for' column you should now see the patron card number. Signed-off-by: David Nind Signed-off-by: Aleisha Amohia Signed-off-by: Lucas Gass * Bug 40172: Replace jQuery with vanilla JS in js/fetch/http-client.js So that we can reuse it from somewhere else. The current need is to be able to reuse it from Cypress tests. Test plan: Try to hit several places where APIClient is used: * Syspref edition * Translation of item type description (be aware of bug 40161) * Delete of cover images * checkin, renew from the checkout list * etc. Note that this does not affect Vue components. Signed-off-by: David Cook Signed-off-by: Pedro Amorim Signed-off-by: Lucas Gass * Bug 36947: Do a locale-based sort for ES facet names This change uses a configurable locale-based collator to sort the ES facet names. Test plan: 0. Apply the patch 1. vi /etc/locale.gen 2. Uncomment the locale you want to generate (e.g. fi_FI.UTF-8 UTF-8) 3. locale-gen 4. vi "/etc/default/koha-common" 5. Add the following to the bottom of the file: export LC_ALL=fi_FI.UTF-8 6. koha-plack --restart koha-common 7. Setup some test records with authors with accented and unaccented names, and different cases for the lead letter e.g. Aa author, Åa author2, aa author, étienne 8. Switch to using Elasticsearch and reindex koha-elasticsearch -b -v --rebuild kohadev 9. Do a test search e.g. http://localhost:8081/cgi-bin/koha/catalogue/search.pl?q=test 10. Confirm the facet names are sorted in ascending order following Finnish collation rules e.g. aa author Aa author étienne Farley, David Humble, Jez Martin, Robert C. Åa author NOTE: Any collation and language can be used. Finnish is just an example of a Latin-based script which has a different alphabetical ordering than just A-Z Signed-off-by: Martin Renvoize Signed-off-by: David Cook Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 36947: Add system preference for configurable locale-based facet sorting This follow-up adds two major enhancements to the locale-based facet sorting implementation: 1. **System Preference Integration** - Adds FacetSortingLocale system preference for configurable locale selection - Dynamically detects available system locales using Koha::I18N - Provides user-friendly dropdown with locale descriptions - Supports both Elasticsearch and Zebra search engines 2. **Zebra Search Engine Support** - Extends locale-based sorting to Zebra (in addition to existing Elasticsearch) - Implements _sort_facets_zebra() function in C4::Search - Maintains consistent Unicode-aware sorting behavior across search engines Key Features: - Dynamic locale detection via Koha::I18N::available_locales() - Proper module architecture with comprehensive unit tests - Clean fallback chain: preference → system LC_COLLATE → default - Admin UI integration in System Preferences → I18N/L10N - Universal facet sorting for international library systems Test plan: 1. Apply patch and restart services 2. Install/run database update 3. Navigate to Administration → System Preferences → I18N/L10N 4. Verify "Sort facet names using" dropdown shows available system locales 5. Test facet sorting with different locales and both search engines 6. Run: prove t/Koha/I18N.t t/Koha/SearchEngine/Elasticsearch/Search.t t/db_dependent/Search_FacetSorting.t Signed-off-by: David Cook Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 36947: (QA follow-up) Add missing POD documentation to Koha::I18N The Koha::I18N module was missing POD documentation. This adds complete documentation for all exported functions including usage examples and descriptions. Signed-off-by: David Cook Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 36947: (QA follow-up) Fix hash key name for locale-list syspref type Signed-off-by: David Cook Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 36947: (QA follow-up) Fix locale-list to show selected values Signed-off-by: David Cook Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 36947: (QA follow-up) Add skippable unit test for fi_FI locale This patch adds a skippable unit test for the fi_FI locale to prove that the patches work well for other locales that don't use the default Unicode collation. It will run on koha-testing-docker, but will be skipped on systems lacking it. This patch also fleshes out the existing unit tests a bit more to prove that the patches also improves the sorting of names with diacritics generally. That is, the default Unicode sort is better than the existing stringwise/bytewise sort even for English and French locales. Test plan: 0. prove -v t/Koha/SearchEngine/Elasticsearch/Search.t \ t/db_dependent/Search_FacetSorting.t Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 36947: (QA follow-up) Add FacetSortingLocale to Search.t mock preferences The test was failing because the new FacetSortingLocale system preference added was not included in the mock preference handler in t/db_dependent/Search.t. This caused warnings about the unknown preference when the _sort_facets_zebra function was called. This commit adds the FacetSortingLocale preference to the mock, returning 'default' as the value, which matches the expected fallback behavior of the new unicode collation sorting feature. Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 36947: DBRev 25.06.00.004 Signed-off-by: Lucas Gass * Populate Library limitations selection with libraries * Get selected reports and save selected reports from edit screen working. * Refactor getting selected lirbaries. * Add library limits info to duplicate section and fix limit info not showing after saving. * Add unit tests for reports_branches updates. * Bug 40370: Remove incorrect DB audit instruction and fix HTML formatting This change removes the incorrect instruction from about.pl: "Run the following SQL to fix the database" and fixes the HTML formatting so that the line "-- Convert schema '' to '':;" is displayed correctly at the start of the line. Test plan: 0. Apply the patch 1. Go to http://localhost:8081/cgi-bin/koha/about.pl?tab=database 2. Note that "Run the following SQL to fix the database" no longer appears and "--Convert schema '' to '':;" starts at the beginning of the line instead of with leading whitespaces. Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 40370: (QA follow-up) Change raw filter to html The diff doesn't contain intentional HTML formatting, and pre tags do not prevent un-escaped HTML from being interpreted, so we should not use the raw filter here Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 34157: Exporting labels as a barcode range can cause 500 error This fixes the error 500 generated when using the label generator if you use the "Bibliographic data precedes barcode" layout type when printing a barcode range. Test plan: 1. Set up information for testing: 1.1 Create a new label layout: 1.1.1 Cataloging > Tools > Label creator 1.1.2 New > Label layout 1.1.3 Add these details: - Layout name: BZ34157 - Choose layout type: Bibliographic data precedes barcode - Select 'List fieds' - Data fields: add some text at the end title, author, isbn, issn, itemtype, barcode, itemcallnumber, 'Some text' 1.1.3 Save 1.2 Ranges of barcode numbers for testing: 1.2.1 Where the numbers are not used in KTD, and are LOWER than the highest barcode number (39999000019193): 500000 to 500100 1.2.3 Where the numbers are not used in KTD, and are HIGHER than the highest barcode number (39999000019193): 39999000020000 to 39999000020100 1.2.2 Where the numbers are used in KTD: 3999900000001 to 3999900001001 2. Print a barcode range using the ranges in 1.2: 2.1 Cataloging > Tools > Label creator > Print barcode range 2.2 Enter the barcode ranges 2.3 Select a layout to be applied: BZ34157 2.4 Export 2.5 Click "Download as PDF" 2.6 Results for all barcode ranges: ==> You get a page with "An error has occured! Error 500...". 3. Repeat step 2, but select the DEFAULT layout for 2.3: ==> Results for all barcode ranges: PDFs with barcode labels successfully generated 4. Apply the patches and restart everything (restart_all) 5. Repeat steps 2 and 3. 6. Results for all barcode ranges and the BZ34157 and DEFAULT layouts: ==> PDFs with barcode labels successfully generated Signed-off-by: Tadeusz „tadzik” Sośnierz Signed-off-by: David Nind Bug 34157: (Follow up) Removed the debugging data Signed-off-by: David Nind Bug 34157: (follow-up) Tidiness fix Signed-off-by: David Nind Signed-off-by: Marcel de Rooy [EDIT] Squashed Signed-off-by: Lucas Gass * Bug 40128: StripWhitespaceChars can create empty subfields When StripWhitespaceChars is enabled and the user by chance enters some white spaces in the input field, Koha generates empty subfield (or even entirely empty field). Test plan: ========== 1. Enable StripWhitespaceChars system preference. 2. Edit an existing record, putting just some spaces into an empty subfield. Save the record. 3. Go to bibliographic record Normal view and in modal "MARC preview" notice that the subfield you entered spaces in exists as an empty subfield. If it was the only subfield in a field, the field exists with no data at all. This is wrong. 4. Apply the patch ; restart_all. 5. Repeat 2. and 3. You should not see any empty subfield now. If the empty subbfield was the only subfield in a field, the field should have been removed from the record. Signed-off-by: Roman Dolny Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40128: Unit tests Signed-off-by: Roman Dolny Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40169: Add a test Signed-off-by: David Nind Amended by: Jonathan Druart Remove .only Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40169: mockData - Do not replace _id if passed If we build an object and pass a primary key (ie. suffixed by _id) we should not replace it. Test plan: The test highlights the problem, it won't affect existing tests. 0. Apply only the first patch (Cypress tests) 1. Run yarn cypress run t/cypress/integration/t/mockData.ts => It fails 2. Apply this patch => It passes Signed-off-by: David Nind Amended-by: Jonathan Druart Remove .only Signed-off-by: Matt Blenkinsop Signed-off-by: Lucas Gass * Bug 40347: Remove warnings from Koha/Hold.t Those diag statements are not really needed # Filling a hold when pref enabled should trigger a test # Filling a hold when pref disabled should not trigger a test # Updating a hold location when pref disabled should not trigger a test # Updating a hold location when pref enabled should trigger a test # Update with no change to pickup location should not trigger a test Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40348: Remove warnings from api/v1/two_factor_auth.t 02:28:36 koha_1 | WARNING: The key derivation method "opensslv1" is deprecated. Using -pbkdf=>'pbkdf2' would be better. 02:28:36 koha_1 | Pass -nodeprecate=>1 to inhibit this message. 02:28:36 koha_1 | at /kohadevbox/koha/Koha/Patron.pm line 3216. We should deal with that on a separate bug report. For now we can remove the warnings from the log/output. Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40353: Remove warnings from Koha/Patron.t C4::Context->userenv not defined! at /kohadevbox/koha/Koha/Patron.pm line 2152. C4::Context->userenv not defined! at /kohadevbox/koha/Koha/Patron.pm line 2152. C4::Context->userenv not defined! at /kohadevbox/koha/Koha/Patron.pm line 2152. We need to mock the userenv Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40351: Remove warning from oha/SearchEngine/Elasticsearch/Search.t Use of uninitialized value in string comparison (cmp) at /kohadevbox/koha/Koha/SearchEngine/Elasticsearch/Search.pm line 536. I think this is the correct fix. We generate a random av category that is used in the data, so $label get undef: 521 $label = $authorised_values{$t}; Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40350: Remove warnings from t/db_dependent/Holds.t Use of uninitialized value in numeric le (<=) at /kohadevbox/koha/C4/Circulation.pm line 3151. Use of uninitialized value in addition (+) at /kohadevbox/koha/C4/Circulation.pm line 3158. Use of uninitialized value in numeric le (<=) at /kohadevbox/koha/C4/Circulation.pm line 3151. Use of uninitialized value in addition (+) at /kohadevbox/koha/C4/Circulation.pm line 3158. Use of uninitialized value in numeric le (<=) at /kohadevbox/koha/C4/Circulation.pm line 3151. Use of uninitialized value in addition (+) at /kohadevbox/koha/C4/Circulation.pm line 3158. $issue->renewal_count is undefined in C4::Circulation:3151, but it's NOT NULL in DB We need to refetch the row to get the default defined at the DB level Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40402: Make xt/find-license-problems.t process files that are in the git index And only those files. Currently the test is failing with 02:52:31 koha_1 | # Failed test at xt/find-license-problems.t line 65. 02:52:31 koha_1 | # got: '0' 02:52:31 koha_1 | # expected: '1' 02:52:33 koha_1 | # File ./misc/translator/po/LICENSE has wrong copyright: hasgpl=1, hasv3=1, hasorlater=1, haslinktolicense=0, hasfranklinst=0 02:52:33 koha_1 | # Looks like you failed 1 test of 1381. 02:52:33 koha_1 | [00:51:24] xt/find-license-problems.t Because a LICENSE file has been added to koha-l10n, and now this test fails on it. https://gitlab.com/koha-community/koha-l10n/-/commit/27ab9ff4d2462c3f95cd54ae4a2e53ce7d2f6a65 But we should not test files that are not part of the git index. Test plan: 0. Do not apply this patch 1. Edit xt/find-license-problems.t, add warn scalar(@files); 2. Run `prove xt/find-license-problems.t` => Notice that 4056 files are processed Note that you need to have a clean git repo. You can run the following git command BUT BEWARE /*\ it will remove all changes not committed `git clean -d -f` 3. Apply this patch, prove again => Tests are passing, with the same number of tests xt/find-license-problems.t .. ok All tests successful. Files=1, Tests=4056 Note that I think we lost one file, as Test::NoWarnings is adding a test. But I don't think it is worth the trouble to find out which one is missing. Signed-off-by: Lucas Gass Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 40171: Fix tt param name Its tran_fail, not tran_error. Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 40171: Remove extraneous join() Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 40171: Return fail if no transports for patron Test plan, k-t-d, don't apply patches yet: 1) Enable ILLModule 2) Create a new ill request at: /cgi-bin/koha/ill/ill-requests.pl?method=create&backend=Standard 3) Pick any type and any library, pick '42' for patron. This is the 'koha' user. 4) Create the request, click 'Send notice to patron'. Pick any template. Notice nothing is shown on the UI. 5) Apply patches. Repeat. Notice you get the message: "The requested notice was NOT queued for delivery by email, SMS". 6) Edit the 'koha' patron and tick the following boxes on 'Patron messaging preferences': - Interlibrary loan ready - Interlibrary loan unavailable 7) Go back to the request and click 'Send notice to patron' and pick any option again. Notice now you get a success message. Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 40344: Fix KohaTable_spec.ts > Cannot read properties of undefined (reading 'description') Not sure since which change this is failing but it has always been wrong. The code in patron-search.inc is: var categories = [% To.json(categories) | $raw %].map(e => { e['_id'] = e.categorycode.toLowerCase(); e['_str'] = e.description; return e; }); var categories_map = categories.reduce((map, e) => { map[e._id] = e; return map; }, {}); It's the keys that are lower cased. Test plan: `yarn cypress run \ --config video=false,screenshotOnRunFailure=false \ --spec t/cypress/integration/KohaTable/KohaTable_spec.ts` should return green Signed-off-by: Matt Blenkinsop Signed-off-by: Lisette Scheer Signed-off-by: Lucas Gass * Bug 40116: Do not display "Patron is already a guarantor..." popup when error occurs If a yellow error message appears when saving the guaranteed patron, also an extra popup message "Patron is already a guarantor for this patron" will appear on the screen. It should only appear when you try to add the same patron as a guarantor that already is a guarantor for that patron. This happens because js function select_user is triggered every time when guarantor data is send back to front-end with variable new_guarantors if error occurs. Already existing guarantors shouldn't be send back to front-end since their data is not lost. This patch changes existing guarantors form elements to use classes "guarantor_id" and "guarantor_relationship" to prevent this. To test: 1. Find a patron with Patron guarantor or add first a Patron guarantor (not a Non-patron guarantor) to a juvenile patron and save. 2. Edit again the same patron with guarantor and modify their age to be greater than the upperage or under the required age of the patron category. => Notice that you will get a yellow message "The following fields are wrong. Please fix them..." => Notice that you will also get a pop up notice that says "Patron is already a guarantor for this patron". 3. Apply this patch. 4. Repeat step 2. => Confirm that yellow message box is displayed but "Patron is..." pop-up is not => Also confirm that guarantors data is not lost. 5. Try to add same patron guarantor as guarantor for guarantee patron again. => Confirm that pop-up is displayed right after attempting to add guarantor. 6. Try to add new guarantor for patron. => New guarantor should be added. 7. Attempt to save the patron. => Confirm that both guarantors data is still displayed in form. 8. Fix patrons age and attempt to save. => Patron is saved and both guarantors are displayed in their details. Sponsored-by: Koha-Suomi Oy Signed-off-by: Owen Leonard Signed-off-by: Aleisha Amohia Signed-off-by: Lucas Gass * Bug 40043: Try to prevent Agreements_spec.ts to fail randomly One test is failing with: """ https://on.cypress.io/element-has-detached-from-dom" type="CypressError"> We initially found matching element(s), but while waiting for them to become actionable, they disappeared from the page. Common situations why this happens: - Your JS framework re-rendered asynchronously - Your app code reacted to an event firing and removed the element You can typically solve this by breaking up a chain. For example, rewrite: > `cy.get('button').click().click()` to > `cy.get('button').as('btn').click()` > `cy.get('@btn').click()` https://on.cypress.io/element-has-detached-from-dom at retryActionability (http://localhost:8081/__cypress/runner/cypress_runner.js:112246:74) at tryCatcher (http://localhost:8081/__cypress/runner/cypress_runner.js:1807:23) at Promise.attempt.Promise.try (http://localhost:8081/__cypress/runner/cypress_runner.js:4315:29) at whenStable (http://localhost:8081/__cypress/runner/cypress_runner.js:143192:68) at (http://localhost:8081/__cypress/runner/cypress_runner.js:143133:14) at tryCatcher (http://localhost:8081/__cypress/runner/cypress_runner.js:1807:23) at Promise._settlePromiseFromHandler (http://localhost:8081/__cypress/runner/cypress_runner.js:1519:31) at Promise._settlePromise (http://localhost:8081/__cypress/runner/cypress_runner.js:1576:18) at Promise._settlePromise0 (http://localhost:8081/__cypress/runner/cypress_runner.js:1621:10) at Promise._settlePromises (http://localhost:8081/__cypress/runner/cypress_runner.js:1701:18) at Promise._fulfill (http://localhost:8081/__cypress/runner/cypress_runner.js:1645:18) at (http://localhost:8081/__cypress/runner/cypress_runner.js:5450:46) From Your Spec Code: at Context.eval (webpack://koha/./t/cypress/integration/ERM/Agreements_spec.ts:630:18)]]> """ My guess is that it happens because we don't wait for the /agreements response. Test plan: Test should still pass, we will see how Jenkins behave after it's pushed. Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40389: Remove t/dummy.t This file should have been removed years ago. See the history: commit a5a419616ddaf81e2a9dc6a87ab92bcf2b336fde Date: Tue Aug 28 01:50:55 2007 +0100 Disable tests @ t/dummy.t:1 @ +# Dummy test until Test::Harness or similar +# is used by the other tests to check deps. +print "1..1\nok 1\n"; Then commit 7f019954460801a5fe480640cf2674dbcca9f625 Date: Fri Dec 7 17:15:22 2007 -0600 installer (part 3): enabled 'make test' - # disable tests - 'test' => {TESTS => 't/dummy.t'}, Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40403: Remove warning from Circulation_holdsqueue.t Use of uninitialized value in addition (+) at /kohadevbox/koha/C4/Biblio.pm line 3049. The context is: 3045 my $current_issues = $biblioitem->totalissues // 0; 3046 if ( defined $value ) { 3047 $totalissues = $value; 3048 } else { 3049 $totalissues = $biblioitem->totalissues + $increase; 3050 } 3051 return 0 if $current_issues == $totalissues; # No need to update if no changes It feels correct to use $current_issues to suppress the warning Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40380: Remove warnings from Patrons/Import.t - Use of uninitialized value $csvkeycol{"dateexpiry"} in array element Use of uninitialized value $csvkeycol{"dateexpiry"} in array element at /kohadevbox/koha/Koha/Patrons/Import.pm line 310, <$handle_2> line 2. Use of uninitialized value $csvkeycol{"dateexpiry"} in array element at /kohadevbox/koha/Koha/Patrons/Import.pm line 310, <$handle_3> line 2. Use of uninitialized value $csvkeycol{"dateexpiry"} in array element at /kohadevbox/koha/Koha/Patrons/Import.pm line 310, <$handle_4> line 2. Use of uninitialized value $csvkeycol{"dateexpiry"} in array element at /kohadevbox/koha/Koha/Patrons/Import.pm line 310, <$fh> line 2. Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40380: Remove warnings from Patrons/Import.t - Argument "" isn't numeric in numeric eq (==) Using perl -MCarp::Always: Argument "" isn't numeric in numeric eq (==) at /usr/share/perl5/DBIx/Class/Row.pm line 1017, <$handle_1> line 2. DBIx::Class::Row::_eq_column_values(Koha::Schema::Result::Borrower=HASH(0x57c409b9ec08), "autorenew_checkouts", "", 1) called at /usr/share/perl5/DBIx/Class/Row.pm line 945 Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40384: Remove warnings from Koha/Plugins/Patron.t t/db_dependent/Koha/Plugins/Patron.t .. 1/5 Plugin error (Test Plugin): Exception 'Koha::Exception' thrown 'patron_barcode_transform called with parameter: test_cn_1' Plugin error (Test Plugin): Exception 'Koha::Exception' thrown 'patron_barcode_transform called with parameter: test_cn_1' Plugin error (Test Plugin): Exception 'Koha::Exception' thrown 'patron_barcode_transform called with parameter: test_cn_1' Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40373: Remove warning from Reserves.t t/db_dependent/Reserves.t .. 10/70 No reserves HOLD_CANCELLATION letter transported by email at /kohadevbox/koha/C4/Letters.pm line 602. We do not test the notification here, we can simply ignore the letters code. However we do test it later so we need to limit the scope of mock Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40385: Remove warning from Reserves/CancelExpiredReserves.t t/db_dependent/Reserves/CancelExpiredReserves.t .. 3/4 No reserves HOLD_CANCELLATION letter transported by email at /kohadevbox/koha/C4/Letters.pm line 602. Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40388: Remove warning from t/Labels.t Use of uninitialized value $cn_item in sprintf at /kohadevbox/koha/C4/ClassSplitRoutine/LCC.pm line 53. Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40378: Remove warnings from api/v1/biblios.t t/db_dependent/api/v1/biblios.t .. 12/15 DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Duplicate entry 'cZt7U7mP0KD' for key 'itembarcodeidx' at /kohadevbox/koha/Koha/Obj ect.pm line 174 t/db_dependent/api/v1/biblios.t .. 13/15 DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Duplicate entry 'N44vCoe4tX41' for key 'itembarcodeidx' at /kohadevbox/koha/Koha/Ob ject.pm line 174 Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40390: Remove warnings from t/db_dependent/Biblio.t t/db_dependent/Biblio.t .. 2/25 Finding auth type GENRE/FORM at t/db_dependent/Biblio.t line 300. Finding auth type PERSO_NAME at t/db_dependent/Biblio.t line 300. Finding auth type PERSO_NAME at t/db_dependent/Biblio.t line 300. Finding auth type PERSO_NAME at t/db_dependent/Biblio.t line 300. Finding auth type PERSO_NAME at t/db_dependent/Biblio.t line 300. t/db_dependent/Biblio.t .. 12/25 Finding auth type TOPIC_TERM at t/db_dependent/Biblio.t line 300. Finding auth type TOPIC_TERM at t/db_dependent/Biblio.t line 300. Finding auth type TOPIC_TERM at t/db_dependent/Biblio.t line 300. Finding auth type PERSO_NAME at t/db_dependent/Biblio.t line 300. Finding auth type PERSO_NAME at t/db_dependent/Biblio.t line 300. Finding auth type PERSO_NAME at t/db_dependent/Biblio.t line 300. t/db_dependent/Biblio.t .. ok Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 38102: Fix limit to 50 items in the checkout history - OPAC Checkout history does not limit to 50 items, it's a regression from bug 33949. To limit to 50 items we need to use "rows", not "limit". Test plan: Have more than 50 checkouts and confirm that by default the table only displays 50 entries. Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 38102: Fix default sort order DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Unknown column 'date_due desc' in 'order clause' at /kohadevbox/koha/Koha/Objects.pm line 401 Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40419: Changes to testing logic This patch makes a couple changes to the tests: * Remove check for Copyright line. The Copyright line should not be mandatory. * Remove dependency of GPL-related checks on the copyrigth line existence. (this highlights several missed checks). * Skip testing-related templates. Koha ships some templates that are not excluded correctly. This 'fix' will highlight existing errors that were skipped until now. To test: 1. Run: $ ktd --shell k$ prove xt/find-license-problems.t => FAIL: Tests pass! Some files should make them fail! 2. Apply this patch 3. Repeat 1 => SUCCESS: Tests fail! Signed-off-by: Jonathan Druart Signed-off-by: Lucas Gass * Bug 40419: Fix wrong license Signed-off-by: Jonathan Druart Signed-off-by: Lucas Gass * Bug 40304: Zebrasrv configs now work on ARM CPUs This patch adds more module search paths to the zebra-biblios-dom.cfg and zebra-authorities-dom.cfg, so that a larger range of CPU architectures will work with Zebra search unit tests. This will not change Debian package installs, but it will fix any git-based installs. TO TEST (you'll need access to an ARM-based CPU, and, preferably, an x86-64 machine): ON THE ARM-BASED MACHINE: a) start ktd, then ktd --shell b) in ktd, run: prove -v t/db_dependent/Search.t c) notice how the test now fails APPLY PATCH d) rerun step b e) notice how the test now passes ON THE X86-64-BASED MACHINE: f) run steps a-e g) notice how the test passes, both before and after applying the patch SIGN OFF Signed-off-by: Paul Derscheid Signed-off-by: Tomas Cohen Arazi Signed-off-by: Lucas Gass * Bug 38966: Fix wrong POD in Koha/CoverImages.pm and Koha/Acquisition/Order/Claims.pm Test plan: 1. perldoc Koha/Acquisition/Order/Claims.pm 2. Check that it mentions Koha::Acquisition::Order::Claims 3. perldoc Koha/CoverImages.pm 4. Check that it mentions Koha::CoverImages.pm 4. These files no longer mention 'Koha::Cities' Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40421: Make HTML elements data attributes Test Plan: 1. Apply patch 2. In Staff Interface inspect element and notice HTML has data attributes Signed-off-by: Lucas Gass Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 39997: List of closed serials: reopening shouldn't require the syspref RoutingSerials Test plan: 1 - Create a closed serial 2 - Disable the syspref "RoutingSerials" 3 - Go to cgi-bin/koha/serials/serials-search.pl and search for the closed serial ; click on the "closed" panel of the result -> on the actions button, there is no option to reopen 4 - Apply patch 5 - Repeat 3, there is now an option to reopen. Signed-off-by: Owen Leonard Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40438: Remove warnings from Koha/Old/Hold.t it's an integer. t/db_dependent/Koha/Old/Hold.t .. 1/3 Value not allowed for auto_incr biblionumber in Biblio at /kohadevbox/koha/t/lib/TestBuilder.pm line 431. Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40437: Remove warning from Koha/Installer.t t/db_dependent/Koha/Installer.t .. 1/4 Use of uninitialized value $db_version in numeric eq (==) at /kohadevbox/koha/Koha/Installer.pm line 32. Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40429: Remove warnings from Koha/Patron/Modifications.t t/db_dependent/Koha/Patron/Modifications.t .. 1/7 DBIx::Class::Storage::DBI::insert(): Missing value for primary key column 'borrowernumber' on BorrowerModification - perhaps you forgot to set its 'is_auto_increme nt' attribute during add_columns()? Treating 'borrowernumber' implicitly as an autoinc, and attempting value retrieval at /kohadevbox/koha/Koha/Object.pm line 174 t/db_dependent/Koha/Patron/Modifications.t .. 5/7 DBIx::Class::Storage::DBI::insert(): Missing value for primary key column 'verification_token' on BorrowerModification - perhaps you forgot to set its 'is_auto_inc rement' attribute during add_columns()? Treating 'verification_token' implicitly as an autoinc, and attempting value retrieval at /kohadevbox/koha/Koha/Object.pm line 174 Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40411: Remove warnings from Koha/SearchEngine/Elasticsearch.t Warnings encountered while roundtripping a MARC record to/from USMARC. Failing over to MARCXML. at t/db_dependent/Koha/SearchEngine/Elasticsearch.t line 854. => This one is expected: we have generated a record with large fields item-level_itypes set but no itemtype set for item (1568) at /kohadevbox/koha/Koha/Schema/Result/Item.pm line 1100. item-level_itypes set but no itemtype set for item (1568) at /kohadevbox/koha/Koha/Schema/Result/Item.pm line 1100. => Those 2 ones can be removed by create a biblio and items using build_sample_biblio and build_sample_item Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40410: Remove warning from Letters. t/db_dependent/Letters.t .. 95/104 Use of uninitialized value in string eq at /kohadevbox/koha/Koha/Patron.pm line 389. contactname can be NULL in DB. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40409: Make Overdues.t fail The test is wrong, the item is not correctly checked in, it should fail. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40409: Remove warnings from t/db_dependent/Overdues.t The tests was wrong, we should make sure the item has been checked in. We were missing the mock userenv: Can't use an undefined value as a HASH reference at /kohadevbox/koha/C4/Circulation.pm line 2744. at /kohadevbox/koha/C4/Circulation.pm line 2787 Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40406: Remove warnings from selenium/basic_workflow.t t/db_dependent/selenium/basic_workflow.t .. 1/22 CP main = 1.93 t/db_dependent/selenium/basic_workflow.t .. 3/22 CP add patron category = 3.56 t/db_dependent/selenium/basic_workflow.t .. 5/22 CP add patron = 4.31 CP add biblio = 0.29 t/db_dependent/selenium/basic_workflow.t .. 11/22 CP add items = 9.81 t/db_dependent/selenium/basic_workflow.t .. 16/22 CP checkout = 5.97 t/db_dependent/selenium/basic_workflow.t .. 20/22 CP checkin = 4.04 t/db_dependent/selenium/basic_workflow.t .. 22/22 CP holds = 5.60 t/db_dependent/selenium/basic_workflow.t .. ok This has been used in the past for benchmarking Koha. I suggest to keep the warn but comment it. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40404: Remove diag from t/Test/Mock/Logger.t t/Test/Mock/Logger.t .. 1/10 # trace: # (No trace messages) # debug: # "Debug message" at /usr/share/perl/5.36/Test/Builder.pm line 374 # info: # (No info messages) # warn: # (No warn messages) # error: # (No error messages) # fatal: # (No fatal messages) t/Test/Mock/Logger.t .. ok All tests successful. Files=1, Tests=10, 0 wallclock secs ( 0.03 usr 0.00 sys + 0.40 cusr 0.07 csys = 0.50 CPU) Result: PASS This one is a bit tricky: we cannot use Test::Warn to capture the output because Test::Builder->diag does not write directly to STDERR. It has its own failure_output handle (which defaults to STDERR) but bypasses Perl’s standard layers. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40381: Remove warning from Koha/SearchEngine/Elasticsearch/ExportConfig.t DBIx::Class::Storage::DBI::insert(): Missing value for primary key column 'filter' on SearchMarcToField - perhaps you forgot to set its 'is_auto_increment' attribute during add_columns()? Treating 'filter' implicitly as an autoinc, and attempting value retrieval at /kohadevbox/koha/Koha/SearchField.pm line 42 Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40377: Remove warnings from HoldsQueue/TransportCostOptimizations.t UseTransportCostMatrix set to yes, but matrix not populated at /kohadevbox/koha/C4/HoldsQueue.pm line 188. UseTransportCostMatrix set to yes, but matrix not populated at /kohadevbox/koha/C4/HoldsQueue.pm line 188. It seems that they are expected, we simply need to catch them. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40376: Remove warning from AuthorisedValues.t t/db_dependent/AuthorisedValues.t .. 1/17 DBIx::Class::Storage::DBI::insert(): Missing value for primary key column 'tagsubfield' on MarcSubfieldStructure - perhaps you forgot to set its 'is_auto_increment' attrib ute during add_columns()? Treating 'tagsubfield' implicitly as an autoinc, and attempting value retrieval at /kohadevbox/koha/Koha/Object.pm line 174 It is a bit scary but it's only that we forgot to pass a value for tagsubfield (that is NOT NULL and part of the PK) Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40374: Remove warnings from Koha/Booking.t t/db_dependent/Koha/Booking.t .. 1/2 DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Duplicate entry '7' for key 'PRIMARY' at /kohadevbox/koha/Koha/Object.pm line 174 DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Data truncated for column 'status' at row 1 at /kohadevbox/koha/Koha/Object.pm line 174 Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40372: Remove warning from api/v1/holds.t t/db_dependent/api/v1/holds.t .. 1/16 No reserves HOLD_CANCELLATION letter transported by email at /kohadevbox/koha/C4/Letters.pm line 602. We do not test the notification here, we can simply ignore the letters code Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Pass the current branch as the filter branchcode * Fix library limit method issue by defining use statements * Filtering the list based on the library limits works * Bug 40173: Make http-client reusable from Cypress tests We will need to call REST API endpoints from Cypress tests, and more specifically from Cypress's tasks. It will be useful to reuse what has been done in http-client.js instead of using the low-level fetch JS function. 1. Add missing get and getAll functions 2. Allow overwrite of return_response and mark_submitting 3. Add a "default" client that will bring flexibility (can call any routes) 4. Add rspack config to generate t/cypress/plugins/dist/api-client.cjs.js that will make it reusable from Cypress's tasks Signed-off-by: Owen Leonard Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40173: Return the response early if the caller needs it We returned the response too late: if something was wrong we processed the response already and thrown an error. This may introduce side-effects but it feels like a correct change. Signed-off-by: Owen Leonard Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40173: Add test for the api-client Cypress plugin Signed-off-by: Owen Leonard Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40173: Remove Cypress warnings Cypress Warning: Cypress detected that you returned a promise in a test, but also invoked one or more cy commands inside of that promise. Signed-off-by: Owen Leonard Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40174: Allow proper E2E testing with Cypress This is the first step toward implementing true end-to-end testing with Cypress. Until now, we have been mocking responses using cy.intercept(), but this approach can lead to confusion. In some cases, we have even had to mock global JavaScript variables, which makes the code unnecessarily complex and unconventional (e.g. win.categories_map). All the bug reports listed under this tree have helped lay the groundwork for this patch. With it, we are able to build mock objects (via plugin mockData) and insert them directly into the database (insertData). Once the tests are complete, we’ll restore the database to its previous state by removing any data generated during the tests. The tests in KohaTable/Holdings_spec.ts have been updated to leverage this new setup. Additionally, a caching mechanism has been added to prevent _id attributes from being generated with the same values (a rare issue we occasionally encountered). While this is still not a perfect solution, it introduces a solid foundation for future improvements. Test plan: All Cypress tests must pass Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40174: Introduce Cypress auth plugin So we can easily retrieve the value for the Authorization header. Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40174: Use api-client Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40174: Deal with enum Data too long for column 'checkprevcheckout' Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40174: Set minLength to 3 When we generate several objects we often get "Duplicate ID" from the server. This mostly happens when the tests failed previously and the objects have not been removed from the DB. Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40174: Require RESTBasicAuth turned ON From MM thread https://chat.koha-community.org/koha-community/pl/aptoodssm7gu8x491onfgxs1xr Cypress tests need RESTBasicAuth - I’m stuck in a chicken-and-egg problem being eaten by its own tail... I need advice. Some Cypress tests need RESTBasicAuth, but it's disabled by default. My plan was to turn it on globally (ie. set before any tests, and reset to its original value after) but we cannot right now: Update in DB could work, but its cached Call the svc script won't work, as we are not logged in yet (and this script require the session cookie) so, I have a lot of solutions, but not sure which one to pick * have a "flush cache" route (smells the rabbit hole) * login to get the cookie, set the syspref via the svc script, logout (ugly, and will slower the cypress tests) * require the pref on for cypress tests * ? I would opt now for the third option, turn it on in Jenkins when we run the cypress tests. And explode for devs when the pref is not set. What do you think? If we push this as it, Jenkins is going to fail. We need to restructure how Jenkins is running the Cypress tests anyway: we need a dedicated job to run them all. We will turn ON the syspref for this job. Signed-off-by: Matt Blenkinsop Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40174: Do not generate bigint Prevent "Out of range value for column 'deliverytime'" in a later follow-up bug reports. Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40180: (bug 40118 follow-up) Add Cypress tests This patch heavily reuses what has been introduced by the previous patches in the tree, and add a insertSampleHold task to be reusable easily in other tests. Test plan: All Cypress tests must pass Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40180: Add tests for insertSampleHold Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40180: Improve deleteSampleObjects We want the task to accept an Object or an Array of Objects Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40346: Introduce loginOpac and visitOpac - Cypress To be able to test the OPAC interface we need to add those 2 new commands Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40346: Add tests Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40346: Use KOHA_INTRANET_URL for the baseUrl This will prevent the test to reload when the URL changes See https://github.com/cypress-io/cypress/issues/2777 Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40181: Make sure data won't be added by insertData We are here testing that data inserted by insertData tasks can be easily removed from the DB using deleteSampleObjects Test plan: Cypress test t/cypress/integration/t/insertData.ts must pass Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40301: Add insertSampleCheckout Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40301: (bug 40299 follow-up) Add Cypress tests Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40345: Pass a patron to insertSampleCheckout So we won't generate a new patron per checkout Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40345: Add insertSamplePatron So it's easier to build and insert a new patron Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40345: Force checkout Pass the confirmation token to force the checkout Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40345: Add tests for bug 38102 Test plan: yarn cypress run --spec t/cypress/integration/KohaTable/OPACCirculationHistory_spec.ts must return green Revert commits from bug 38102 Run again the Cypress tests => They fail Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40345: Properly cleanup old checkouts Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40345: Use then to prevent async issues Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40433: Add missing maxLength to item, library and patron The test added in xt/api.t was not fully accurate, we skipped the columns that have the same name as the api attribute (ie. the ones not part of to_api_mapping) Test plan: prove xt/api.t should pass Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40430: Fix Toolbar_spec.ts See comment 1 on the bug. We are adding the capability to insert vendors and baskets. Test plan: Confirm that yarn cypress run t/cypress/integration/Toolbar_spec.ts pass, even if you do not have any vendors in DB. Signed-off-by: Owen Leonard Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40318: (bug 40067 follow-up) Prevent receive shipments opening in a new tab - vendor list view 1. Acquisitions > Search vendors > Search 2. In the actions column, click "Receive shipments" => Without this patch the receive shipment from vendor [name] page opens in a new tab/window => With this patch applied it does not Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40318: Add tests Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40447: Add comprehensive JSDoc documentation to Cypress plugins This patch adds detailed JSDoc documentation to all Cypress testing plugin files. Documentation added to: - insertData.js: Data insertion utilities with examples - api-client.js: API wrapper functions with usage patterns - mockData.js: Schema-based mock data generation - auth.js: Authentication helper functions - db.js: Database query utilities - readYamlFile.js: YAML file reading utilities - index.js: Main plugin configuration Each function now includes: - Complete parameter descriptions with types - Return value documentation - Practical usage examples - Error conditions and handling - Module-level overviews This addresses the documentation gap identified during QA review, hopefully making it easier for future devs to adopt the new framework of tools. Signed-off-by: Lucas Gass * Bug 40379: Remove warnings from t/db_dependent/www XMLin complains because there are several nodes with the same name attribute. Not sure what is correct or not, but we actually cannot use the admin/DBMS user to login to the Koha interface. We use KOHA_USER env var or default to 'koha'. Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Lucas Gass * Bug 40401: Implement Koha::Patron->is_anonymous The first motivation of this patch is to remove the following warnings from t/db_dependent/Auth.t: Use of uninitialized value $anonymous_patron in string eq at /kohadevbox/koha/C4/Auth.pm line 1497 Actually a correct fix seems to add a new `is_anonymous` method to Koha::Patron in order to remove the warnings from everywhere else. Test plan: Confirm that you cannot log in using the anonymous patron and that the 2 tests are passing prove t/db_dependent/Auth.t t/db_dependent/Koha/Patron.t Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40401: (follow-up) Fix grammar and rollback in tests - Fixed grammar: "Returns true if the patron is the anonymous patron" - Fixed test cleanup: use txn_rollback instead of txn_begin - Fixed test subroutine closure syntax Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 40407: Remove legacy "pre-wrap" versions From https://css-tricks.com/snippets/css/make-pre-text-wrap/ /* Browser specific (not valid) styles to make preformatted text wrap */ pre { white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } ... I think it's now safe to remove the backward compatibility versions and simply keep pre-wrap. Test plan (from bug 921)0: * place a hold on a title with a very very long title or author * mark it as "waiting for pickup" by doing a checkin * go to command line interface, and run * misc/cronjobs/gather_print_notices.pl /tmp * misc/cronjobs/printoverdues.sh /tmp * if your title/author is long enough, it's splitted on 2 lines with this patch (it is not before this patch) It will also remove the warnings from t/db_dependent/Patron/Borrower_Discharge.t WARNING: Ignored `white-space: -moz-pre-wrap` at 6:14, invalid value. WARNING: Ignored `white-space: -o-pre-wrap` at 7:14, invalid value. WARNING: Ignored `word-wrap: break-work` at 8:14, invalid value. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 18772: Remove warnings from t/ImportBatch.t Use of uninitialized value in concatenation (.) or string at /usr/local/share/perl/5.20.2/MARC/File/XML.pm line 399, <__ANONIO__> chunk 1. Those are 2 warnings coming from MARC::File::XML when called with invalid XML. We should not use Test::Warn as they are not expected and that may be fixed upstream. Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Lucas Gass * Bug 32296: Capitalization - UNIMARC labels for 181$b value builder This patch changes the capitalisation for the labels displayed in the MARC editor for UNIMARC 181$b, when the value builder unimarc_field_181b.pl is used. The labels are changed from capital case to sentence case, to be consistent with other labels: - Specification of type (position 0) - Specification of motion (position 1) - Specification of dimensionality (position 2) - Sensory specification 1, 2 and 3 (positions 3 to 5) Test plan: 1. Check the capitalisation in the patch. Signed-off-by: David Nind Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 32284: Fix capitalization for UNIMARC value builders This patch changes the capitalization for the labels displayed in the MARC tag editor for UNIMARC subfields 181$a, 181$c, $182$a, 182$c, and 183$c, when the value builders are used. The labels are changed from capital case to sentence case, for consistency with other labels: - Content Form -> Content form (181$a) - Content Type -> Content type (181$c) - Media Type Code -> Media type code (182$a) - Media Type -> Media type (182$c) - In the dropdown list (183$a): . Audio Carriers -> Audio carriers . Computer Carriers -> Computer carriers . Microform Carriers -> Microform carriers . Microscopic Carriers -> Microscopic carriers . Stereographic Carriers -> Stereographic carriers Test plan: 1. In your KTD shell navigate to koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/value_builder 2. Run "git grep Audio Carriers" you should get results 3. Run "git grep Computer Carriers" you should get results 4. Run "git grep Content Form" you should get results 5. Run "git grep Content Type" you should get results 6. Run "git grep Media Type" you should get results 7. Run "git grep Media Type Code" you should get results 8. Run "git grep Microform Carriers" you should get results 9. Run "git grep Microscopic Carriers" you should get results 10. Apply the patch 11. Repeat steps 2-9 you should not get results Signed-off-by: David Nind Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 32287: Capitalization - UNIMARC labels for 214$r and $s This patch changes the capitalisation for the labels displayed in the OPAC and staff interface for UNIMARC 214$r and $s from capital case to sentence case, to be consistent with other labels: - 214$r: Printing and/or publishing information transcribed as found in the main source of information - 214$s: Printing and/or publishing information transcribed as found in the colophon Test plan: 1. Have a look at the patch and confirm the changes look correct. Signed-off-by: David Nind Signed-off-by: Emily Lamancusa Signed-off-by: Lucas Gass * Bug 40458: add pod coverage to Discharge.pm Signed-off-by: Marcel de Rooy [EDIT] Replaced borrowers in the ->request POD by borrower Signed-off-by: Lucas Gass * Bug 40174: Fix codespell Signed-off-by: Jonathan Druart * Remove comments. --------- Signed-off-by: Caroline Cyr La Rose Signed-off-by: Baptiste Wojtkowski Signed-off-by: Lucas Gass Signed-off-by: Roman Dolny Signed-off-by: Emily Lamancusa Signed-off-by: David Nind Signed-off-by: Marcel de Rooy Signed-off-by: Paul Derscheid Signed-off-by: Martin Renvoize Signed-off-by: Michelle Spinney Signed-off-by: Tomas Cohen Arazi Signed-off-by: Kristi Krueger Signed-off-by: Jonathan Druart Signed-off-by: Lisette Scheer Signed-off-by: Anneli Österman Signed-off-by: David Cook Signed-off-by: Andrew Fuerste Henry Signed-off-by: Aleisha Amohia Signed-off-by: Emmanuel Bétemps Signed-off-by: Andrew Auld Signed-off-by: Laura_Escamilla Signed-off-by: Ray Delahunty Signed-off-by: David Flater Signed-off-by: Heather Hernandez Signed-off-by: Pedro Amorim Signed-off-by: Felicie Signed-off-by: Matt Blenkinsop Signed-off-by: Eric Garcia Signed-off-by: Brendan Lawlor Signed-off-by: Kyle M Hall Signed-off-by: Owen Leonard Co-authored-by: Pedro Amorim Co-authored-by: Baptiste Wojtkowski Co-authored-by: Lucas Gass Co-authored-by: Emily Lamancusa Co-authored-by: Owen Leonard Co-authored-by: David Nind Co-authored-by: Marcel de Rooy Co-authored-by: Nick Clemens Co-authored-by: Martin Renvoize Co-authored-by: Paul Derscheid Co-authored-by: Tomas Cohen Arazi Co-authored-by: Matt Blenkinsop Co-authored-by: PhilipOrr Co-authored-by: Mason James Co-authored-by: Caroline Cyr La Rose Co-authored-by: Emmi Takkinen Co-authored-by: Aleisha Amohia Co-authored-by: Laura_Escamilla Co-authored-by: Lisette Scheer Co-authored-by: Cameron E. Tidd Co-authored-by: Martin Renvoize Co-authored-by: Jonathan Druart Co-authored-by: Fridolin Somers Co-authored-by: John Doe Co-authored-by: Andrii Nugged Co-authored-by: Lari Strand Co-authored-by: Andrew Fuerste Henry Co-authored-by: nina martinez Co-authored-by: Janusz Kaczmarek Co-authored-by: David Cook Co-authored-by: Matthias Le Gac Co-authored-by: Pedro Amorim Co-authored-by: Jake Deery Co-authored-by: Doris Tam Co-authored-by: Eric Garcia Co-authored-by: Toni Gardiner Co-authored-by: Cath Leone Co-authored-by: Brian Norris --- C4/Auth.pm | 6 +- C4/Biblio.pm | 138 +--- C4/Circulation.pm | 10 +- C4/ClassSplitRoutine/LCC.pm | 2 +- C4/Form/MessagingPreferences.pm | 45 ++ C4/Items.pm | 12 +- C4/Koha.pm | 2 +- C4/Labels/Label.pm | 8 +- C4/SIP/ILS/Transaction/Checkout.pm | 6 +- C4/Scrubber.pm | 4 +- C4/Search.pm | 42 +- Koha.pm | 2 +- Koha/Acquisition/Order/Claims.pm | 2 +- Koha/BackgroundJob/BatchUpdateItem.pm | 2 +- Koha/Biblio.pm | 213 +++--- Koha/CookieManager.pm | 130 +++- Koha/Course.pm | 20 +- Koha/Course/Instructor.pm | 20 +- Koha/Course/Instructors.pm | 20 +- Koha/Course/Item.pm | 20 +- Koha/Course/Items.pm | 20 +- Koha/Course/Reserve.pm | 20 +- Koha/Course/Reserves.pm | 20 +- Koha/Courses.pm | 20 +- Koha/CoverImages.pm | 2 +- Koha/Devel/Files.pm | 192 +++++ Koha/Encryption.pm | 5 +- Koha/Exceptions/MarcOverlayRule.pm | 20 +- Koha/Filter/MARC/TrimFields.pm | 10 +- Koha/Hold.pm | 3 + Koha/I18N.pm | 262 +++++++ Koha/ILL/Backend/Standard.pm | 17 +- Koha/ILL/Request.pm | 2 + Koha/Import/OAI/Authorities.pm | 1 + Koha/Import/OAI/Authority.pm | 1 + Koha/Import/OAI/Biblio.pm | 1 + Koha/Import/OAI/Biblios.pm | 1 + Koha/Installer.pm | 2 +- Koha/Item.pm | 18 + Koha/Items.pm | 9 +- Koha/Manual.pm | 1 + Koha/Patron.pm | 184 ++++- Koha/Patron/Discharge.pm | 92 +++ Koha/Patrons/Import.pm | 8 +- Koha/Quotes.pm | 2 +- Koha/REST/V1/CirculationRules.pm | 20 +- Koha/REST/V1/Holds.pm | 31 +- Koha/REST/V1/Suggestions.pm | 17 +- Koha/Report.pm | 20 +- Koha/Reports.pm | 29 +- Koha/Schema/Result/Borrower.pm | 12 +- Koha/Schema/Result/Category.pm | 12 +- Koha/Schema/Result/Deletedborrower.pm | 12 +- Koha/Schema/Result/ReportsBranch.pm | 85 +++ Koha/Schema/Result/SavedSql.pm | 220 ++++++ Koha/SearchEngine/Elasticsearch/Search.pm | 49 +- acqui/basket.pl | 10 +- acqui/newordersuggestion.pl | 26 +- admin/columns_settings.yml | 7 +- admin/preferences.pl | 12 + api/v1/swagger/definitions/item.yaml | 14 + api/v1/swagger/definitions/library.yaml | 4 + api/v1/swagger/definitions/patron.yaml | 15 + api/v1/swagger/definitions/patron_category.yaml | 7 + api/v1/swagger/paths/holds.yaml | 18 + catalogue/moredetail.pl | 9 +- catalogue/updateitem.pl | 10 +- cataloguing/addbiblio.pl | 5 +- cataloguing/additem.pl | 7 +- circ/circulation.pl | 2 +- cpanfile | 1 + cypress.config.ts | 11 +- debian/build-git-snapshot | 102 ++- debian/control | 3 + debian/templates/koha-conf-site.xml.in | 8 +- debian/templates/zebra-authorities-dom-site.cfg.in | 2 +- debian/templates/zebra-biblios-dom-site.cfg.in | 2 +- docs/teams.yaml | 171 +++-- etc/koha-conf.xml | 8 +- etc/zebradb/zebra-authorities-dom.cfg | 2 +- etc/zebradb/zebra-biblios-dom.cfg | 2 +- ill/ill-requests.pl | 4 +- installer/data/mysql/db_revs/250600001.pl | 20 + installer/data/mysql/db_revs/250600002.pl | 40 + installer/data/mysql/db_revs/250600003.pl | 32 + installer/data/mysql/db_revs/250600004.pl | 22 + installer/data/mysql/en/optional/sample_news.yml | 12 +- installer/data/mysql/kohastructure.sql | 19 +- installer/data/mysql/mandatory/sysprefs.sql | 5 +- installer/data/mysql/updatedatabase.pl | 16 + koha-tmpl/intranet-tmpl/lib/jsdiff/jsdiff.js | 2 +- koha-tmpl/intranet-tmpl/lib/jsdiff/jsdiff.min.js | 2 +- .../intranet-tmpl/prog/css/src/staff-global.scss | 10 + .../intranet-tmpl/prog/en/includes/about-team.inc | 71 +- .../batch_item_record_modification.inc | 7 + .../en/includes/catalogue/itemsearch_item.csv.inc | 4 +- .../en/includes/catalogue/itemsearch_item.json.inc | 4 +- .../includes/csv_headers/catalogue/itemsearch.tt | 2 +- .../prog/en/includes/guided-reports-view.inc | 6 +- .../intranet-tmpl/prog/en/includes/header.inc | 18 +- .../prog/en/includes/html-customization-help.inc | 2 + .../en/includes/member-display-address-style.inc | 50 +- .../prog/en/includes/patron_messages.inc | 46 +- .../intranet-tmpl/prog/en/includes/prefs-menu.inc | 11 + .../intranet-tmpl/prog/en/includes/tools-menu.inc | 2 +- koha-tmpl/intranet-tmpl/prog/en/modules/about.tt | 11 +- .../intranet-tmpl/prog/en/modules/acqui/basket.tt | 25 +- .../prog/en/modules/acqui/newordersuggestion.tt | 15 +- .../prog/en/modules/admin/categories.tt | 8 +- .../prog/en/modules/admin/localization.tt | 5 +- .../prog/en/modules/admin/marctagstructure.tt | 4 +- .../en/modules/admin/preferences/acquisitions.pref | 2 +- .../en/modules/admin/preferences/circulation.pref | 9 +- .../en/modules/admin/preferences/i18n_l10n.pref | 5 + .../prog/en/modules/admin/preferences/opac.pref | 10 +- .../prog/en/modules/admin/preferences/patrons.pref | 10 +- .../prog/en/modules/admin/preferences/reports.pref | 9 + .../modules/admin/preferences/staff_interface.pref | 6 - .../prog/en/modules/admin/search_filters.tt | 20 +- koha-tmpl/intranet-tmpl/prog/en/modules/auth.tt | 2 +- .../prog/en/modules/authorities/authorities.tt | 2 +- .../intranet-tmpl/prog/en/modules/basket/basket.tt | 2 +- .../prog/en/modules/batch/print-notices.tt | 3 - .../prog/en/modules/catalogue/detail.tt | 85 +-- .../prog/en/modules/catalogue/itemsearch.tt | 2 + .../prog/en/modules/catalogue/moredetail.tt | 10 + .../prog/en/modules/cataloguing/addbiblio.tt | 2 +- .../prog/en/modules/cataloguing/addbooks.tt | 6 +- .../prog/en/modules/cataloguing/additem.tt | 2 + .../value_builder/unimarc_field_181a.tt | 2 +- .../value_builder/unimarc_field_181b.tt | 12 +- .../value_builder/unimarc_field_181c.tt | 2 +- .../value_builder/unimarc_field_182a.tt | 2 +- .../value_builder/unimarc_field_182c.tt | 2 +- .../value_builder/unimarc_field_183a.tt | 10 +- .../prog/en/modules/circ/article-requests.tt | 29 +- .../prog/en/modules/circ/branchoverdues.tt | 2 +- .../prog/en/modules/circ/pendingreserves.tt | 2 +- .../prog/en/modules/circ/transferstoreceive.tt | 3 + .../prog/en/modules/circ/waitingreserves.tt | 34 +- .../prog/en/modules/clubs/patron-enroll.tt | 2 +- .../prog/en/modules/members/holdshistory.tt | 12 +- .../prog/en/modules/members/member-flags.tt | 2 +- .../prog/en/modules/members/memberentrygen.tt | 4 +- .../prog/en/modules/members/moremember.tt | 2 +- .../en/modules/reports/guided_reports_start.tt | 47 +- .../prog/en/modules/reports/issues_stats.tt | 72 +- .../prog/en/modules/reports/itemslost.tt | 2 +- .../prog/en/modules/reports/orders_by_budget.tt | 2 +- .../prog/en/modules/reports/reports-home.tt | 29 +- .../prog/en/modules/serials/serials-search.tt | 24 +- .../prog/en/modules/tools/additional-contents.tt | 2 +- .../en/modules/tools/batch_extend_due_dates.tt | 1 + .../prog/en/modules/tools/stage-marc-import.tt | 2 +- .../prog/en/xslt/UNIMARCslimUtils.xsl | 4 +- koha-tmpl/intranet-tmpl/prog/js/datatables.js | 55 +- .../intranet-tmpl/prog/js/fetch/api-client.js | 2 + .../prog/js/fetch/default-api-client.js | 19 + .../intranet-tmpl/prog/js/fetch/http-client.js | 94 ++- .../prog/js/vue/components/ERM/AgreementsList.vue | 2 +- .../prog/js/vue/components/ERM/LicensesList.vue | 6 +- .../prog/js/vue/components/Vendors/VendorList.vue | 2 +- .../intranet-tmpl/prog/js/vue/fetch/http-client.js | 48 +- .../opac-tmpl/bootstrap/css/src/_responsive.scss | 5 + koha-tmpl/opac-tmpl/bootstrap/css/src/opac.scss | 51 +- .../opac-tmpl/bootstrap/en/includes/calendar.inc | 2 +- .../opac-tmpl/bootstrap/en/includes/masthead.inc | 1 + .../bootstrap/en/includes/opac-bottom.inc | 4 +- .../bootstrap/en/includes/patron-restrictions.inc | 27 + .../bootstrap/en/includes/subtypes_unimarc.inc | 46 +- .../opac-tmpl/bootstrap/en/includes/usermenu.inc | 9 +- .../opac-tmpl/bootstrap/en/modules/clubs/enroll.tt | 2 +- .../bootstrap/en/modules/opac-addbybiblionumber.tt | 2 +- .../opac-tmpl/bootstrap/en/modules/opac-browse.tt | 2 +- .../opac-tmpl/bootstrap/en/modules/opac-browser.tt | 2 +- .../bootstrap/en/modules/opac-illrequests.tt | 2 +- .../bootstrap/en/modules/opac-patron-consent.tt | 12 +- .../opac-tmpl/bootstrap/en/modules/opac-reserve.tt | 48 +- .../opac-tmpl/bootstrap/en/modules/opac-results.tt | 12 +- .../bootstrap/en/modules/opac-suggestions.tt | 2 +- .../opac-tmpl/bootstrap/en/modules/opac-tags.tt | 6 +- .../bootstrap/en/modules/opac-tags_subject.tt | 2 +- .../opac-tmpl/bootstrap/en/modules/opac-user.tt | 36 +- .../bootstrap/en/modules/opac-virtual-card.tt | 27 +- .../opac-tmpl/bootstrap/en/modules/sci/sci-main.tt | 43 +- .../opac-tmpl/bootstrap/en/modules/sco/sco-main.tt | 29 +- .../bootstrap/en/xslt/UNIMARCslimUtils.xsl | 4 +- koha-tmpl/opac-tmpl/bootstrap/js/browse.js | 4 +- koha-tmpl/opac-tmpl/bootstrap/js/timeout.js | 39 - members/holdshistory.pl | 7 - members/memberentry.pl | 13 +- members/moremember.pl | 4 - members/readingrec.pl | 5 +- misc/cronjobs/overdue_notices.pl | 3 - misc/devel/Koha/Schema/Result/ReportsBranch.pm | 85 +++ misc/devel/tidy.pl | 67 +- .../maintenance/search_for_data_inconsistencies.pl | 2 +- misc/sip_cli_emulator.pl | 34 +- opac/opac-readingrecord.pl | 10 +- opac/opac-reserve.pl | 78 +- opac/opac-user.pl | 1 + opac/sci/sci-main.pl | 4 + opac/sco/sco-main.pl | 7 + package.json | 2 +- reports/guided_reports.pl | 105 ++- reports/orders_by_fund.pl | 26 +- rspack.config.js | 34 + t/CookieManager.t | 97 ++- t/Form_MessagingPreferences.t | 78 +- t/ImportBatch.t | 24 +- t/Koha/I18N.t | 48 +- t/Koha/SearchEngine/Elasticsearch/Search.t | 127 +++- t/Labels.t | 6 +- t/RecordProcessor.t | 10 +- t/Scrubber.t | 218 ++++-- t/Test/Mock/Logger.t | 20 +- t/cypress/fixtures/{sample.mrc => sample.xml} | 0 t/cypress/integration/Acquisitions/Vendors_spec.ts | 66 ++ t/cypress/integration/Auth/csrf.ts | 66 +- t/cypress/integration/ERM/Agreements_spec.ts | 14 +- t/cypress/integration/ERM/DataProviders_spec.ts | 2 +- t/cypress/integration/ERM/UsageReports_spec.ts | 4 +- .../integration/Islands/AcquisitionsMenu_spec.ts | 10 +- .../KohaTable/CirculationHistory_spec.ts | 23 + t/cypress/integration/KohaTable/Holdings_spec.ts | 576 ++++++-------- t/cypress/integration/KohaTable/KohaTable_spec.ts | 4 +- .../KohaTable/OPACCirculationHistory_spec.ts | 53 ++ .../integration/KohaTable/PatronSearch_spec.ts | 53 +- .../integration/KohaTable/PendingHolds_spec.ts | 101 +++ t/cypress/integration/Toolbar_spec.ts | 81 +- .../integration/Tools/ManageMarcImport_spec.ts | 60 +- t/cypress/integration/t/api-client.ts | 28 + t/cypress/integration/t/commands.ts | 27 + t/cypress/integration/t/db.ts | 15 + t/cypress/integration/t/insertData.ts | 278 +++++++ t/cypress/integration/t/mockData.ts | 20 + t/cypress/plugins/api-client.js | 177 +++++ t/cypress/plugins/auth.js | 40 + t/cypress/plugins/db.js | 66 ++ t/cypress/plugins/index.js | 109 ++- t/cypress/plugins/insertData.js | 825 +++++++++++++++++++++ t/cypress/plugins/mockData.js | 215 +++++- t/cypress/plugins/readYamlFile.js | 31 + t/cypress/support/e2e.js | 34 +- t/db_dependent/Auth.t | 3 +- t/db_dependent/Auth_with_shibboleth.t | 31 +- t/db_dependent/AuthorisedValues.t | 4 +- t/db_dependent/Biblio.t | 18 +- t/db_dependent/Circulation/OfflineCirculation.t | 62 +- t/db_dependent/Circulation_holdsqueue.t | 3 +- t/db_dependent/Holds.t | 5 +- .../HoldsQueue/TransportCostOptimizations.t | 43 +- .../Items/AutomaticItemModificationByAge.t | 106 ++- t/db_dependent/Koha.t | 6 +- t/db_dependent/Koha/Biblio.t | 209 ++++-- t/db_dependent/Koha/Booking.t | 29 +- t/db_dependent/Koha/Hold.t | 49 +- t/db_dependent/Koha/Installer.t | 3 +- t/db_dependent/Koha/Item.t | 54 +- t/db_dependent/Koha/Items/BatchUpdate.t | 67 +- t/db_dependent/Koha/Old/Hold.t | 5 +- t/db_dependent/Koha/Patron.t | 254 ++++++- t/db_dependent/Koha/Patron/Modifications.t | 38 +- t/db_dependent/Koha/Patrons.t | 17 +- t/db_dependent/Koha/Patrons/Import.t | 3 +- t/db_dependent/Koha/Plugins/Patron.t | 8 +- t/db_dependent/Koha/Reports.t | 38 +- t/db_dependent/Koha/SearchEngine/Elasticsearch.t | 32 +- .../Koha/SearchEngine/Elasticsearch/ExportConfig.t | 12 +- .../Koha/SearchEngine/Elasticsearch/Search.t | 3 +- t/db_dependent/Letters.t | 3 +- t/db_dependent/Overdues.t | 10 +- t/db_dependent/Reserves.t | 12 +- t/db_dependent/Reserves/CancelExpiredReserves.t | 12 +- t/db_dependent/SIP/Transaction.t | 21 +- t/db_dependent/Search.t | 2 + t/db_dependent/Search_FacetSorting.t | 119 +++ t/db_dependent/api/v1/biblios.t | 33 +- t/db_dependent/api/v1/holds.t | 258 ++++++- t/db_dependent/api/v1/two_factor_auth.t | 3 +- t/db_dependent/selenium/basic_workflow.t | 7 +- t/db_dependent/selenium/opac_ill_requests.t | 9 +- t/db_dependent/selenium/regressions.t | 11 +- t/db_dependent/www/auth_values_input_www.t | 11 +- t/db_dependent/www/batch.t | 11 +- t/db_dependent/www/history.t | 11 +- t/db_dependent/www/search_utf8.t | 8 +- t/dummy.t | 4 - t/lib/TestBuilder.pm | 7 +- tools/batchMod.pl | 21 +- xt/api.t | 51 +- xt/author/codespell.t | 13 +- xt/author/pod_checker.t | 7 +- xt/author/podcorrectness.t | 8 +- xt/find-license-problems.t | 47 +- xt/find-missing-csrf.t | 11 +- xt/find-missing-filters.t | 12 +- xt/find-missing-op-in-forms.t | 12 +- xt/perltidy.t | 8 +- xt/pl_valid.t | 17 +- xt/single_quotes.t | 11 +- xt/tt_tidy.t | 6 +- yarn.lock | 46 +- 303 files changed, 7863 insertions(+), 2352 deletions(-) create mode 100644 Koha/Devel/Files.pm create mode 100644 Koha/Schema/Result/ReportsBranch.pm create mode 100755 installer/data/mysql/db_revs/250600001.pl create mode 100755 installer/data/mysql/db_revs/250600002.pl create mode 100755 installer/data/mysql/db_revs/250600003.pl create mode 100755 installer/data/mysql/db_revs/250600004.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/reports.pref create mode 100644 koha-tmpl/intranet-tmpl/prog/js/fetch/default-api-client.js create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/includes/patron-restrictions.inc delete mode 100644 koha-tmpl/opac-tmpl/bootstrap/js/timeout.js create mode 100644 misc/devel/Koha/Schema/Result/ReportsBranch.pm rename t/cypress/fixtures/{sample.mrc => sample.xml} (100%) create mode 100644 t/cypress/integration/KohaTable/CirculationHistory_spec.ts create mode 100644 t/cypress/integration/KohaTable/OPACCirculationHistory_spec.ts create mode 100644 t/cypress/integration/KohaTable/PendingHolds_spec.ts create mode 100644 t/cypress/integration/t/api-client.ts create mode 100644 t/cypress/integration/t/commands.ts create mode 100644 t/cypress/integration/t/db.ts create mode 100644 t/cypress/integration/t/insertData.ts create mode 100644 t/cypress/plugins/api-client.js create mode 100644 t/cypress/plugins/auth.js create mode 100644 t/cypress/plugins/db.js create mode 100644 t/cypress/plugins/insertData.js create mode 100755 t/db_dependent/Search_FacetSorting.t delete mode 100755 t/dummy.t diff --git a/C4/Auth.pm b/C4/Auth.pm index 2fa9e2bed7..affc7ee43a 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -1492,10 +1492,6 @@ sub checkauth { my $auth_template_name = ( $type eq 'opac' ) ? 'opac-auth.tt' : 'auth.tt'; my $template = C4::Templates::gettemplate( $auth_template_name, $type, $query ); - my $borrowernumber = $patron and $patron->borrowernumber; - my $anonymous_patron = C4::Context->preference('AnonymousPatron'); - my $is_anonymous_patron = $patron && ( $patron->borrowernumber eq $anonymous_patron ); - $template->param( login => 1, INPUTS => \@inputs, @@ -1530,7 +1526,7 @@ sub checkauth { opac_css_override => $ENV{'OPAC_CSS_OVERRIDE'}, too_many_login_attempts => ( $patron and $patron->account_locked ), password_has_expired => ( $patron and $patron->password_expired ), - is_anonymous_patron => ($is_anonymous_patron), + is_anonymous_patron => ( $patron and $patron->is_anonymous ), password_expiration_date => ( $patron and $patron->password_expiration_date ), date_enrolled => ( $patron and $patron->dateenrolled ), auth_error => $auth_error, diff --git a/C4/Biblio.pm b/C4/Biblio.pm index d847fe8f61..00f481cf96 100644 --- a/C4/Biblio.pm +++ b/C4/Biblio.pm @@ -62,7 +62,6 @@ BEGIN { TransformMarcToKoha TransformHtmlToMarc TransformHtmlToXml - prepare_host_field ); # Internal functions @@ -2998,141 +2997,6 @@ sub ModBiblioMarc { return $biblionumber; } -=head2 prepare_host_field - -$marcfield = prepare_host_field( $hostbiblioitem, $marcflavour ); -Generate the host item entry for an analytic child entry - -=cut - -sub prepare_host_field { - my ( $hostbiblio, $marcflavour ) = @_; - $marcflavour ||= C4::Context->preference('marcflavour'); - - my $biblio = Koha::Biblios->find($hostbiblio); - my $host = $biblio->metadata->record; - - # unfortunately as_string does not 'do the right thing' - # if field returns undef - my %sfd; - my $field; - my $host_field; - if ( $marcflavour eq 'MARC21' ) { - if ( $field = $host->field('100') || $host->field('110') || $host->field('11') ) { - my $s = $field->as_string('ab'); - if ($s) { - $sfd{a} = $s; - } - } - if ( $field = $host->field('245') ) { - my $s = $field->as_string('a'); - if ($s) { - $sfd{t} = $s; - } - } - if ( $field = $host->field('260') ) { - my $s = $field->as_string('abc'); - if ($s) { - $sfd{d} = $s; - } - } - if ( $field = $host->field('240') ) { - my $s = $field->as_string(); - if ($s) { - $sfd{b} = $s; - } - } - if ( $field = $host->field('022') ) { - my $s = $field->as_string('a'); - if ($s) { - $sfd{x} = $s; - } - } - if ( $field = $host->field('020') ) { - my $s = $field->as_string('a'); - if ($s) { - $sfd{z} = $s; - } - } - if ( $field = $host->field('001') ) { - $sfd{w} = $field->data(),; - } - $host_field = MARC::Field->new( 773, '0', ' ', %sfd ); - return $host_field; - } elsif ( $marcflavour eq 'UNIMARC' ) { - - #author - if ( $field = $host->field('700') || $host->field('710') || $host->field('720') ) { - my $s = $field->as_string('ab'); - if ($s) { - $sfd{a} = $s; - } - } - - #title - if ( $field = $host->field('200') ) { - my $s = $field->as_string('a'); - if ($s) { - $sfd{t} = $s; - } - } - - #place of publicaton - if ( $field = $host->field('210') ) { - my $s = $field->as_string('a'); - if ($s) { - $sfd{c} = $s; - } - } - - #date of publication - if ( $field = $host->field('210') ) { - my $s = $field->as_string('d'); - if ($s) { - $sfd{d} = $s; - } - } - - #edition statement - if ( $field = $host->field('205') ) { - my $s = $field->as_string(); - if ($s) { - $sfd{e} = $s; - } - } - - #URL - if ( $field = $host->field('856') ) { - my $s = $field->as_string('u'); - if ($s) { - $sfd{u} = $s; - } - } - - #ISSN - if ( $field = $host->field('011') ) { - my $s = $field->as_string('a'); - if ($s) { - $sfd{x} = $s; - } - } - - #ISBN - if ( $field = $host->field('010') ) { - my $s = $field->as_string('a'); - if ($s) { - $sfd{y} = $s; - } - } - if ( $field = $host->field('001') ) { - $sfd{0} = $field->data(),; - } - $host_field = MARC::Field->new( 461, '0', ' ', %sfd ); - return $host_field; - } - return; -} - =head2 UpdateTotalIssues UpdateTotalIssues($biblionumber, $increase, [$value]) @@ -3182,7 +3046,7 @@ sub UpdateTotalIssues { if ( defined $value ) { $totalissues = $value; } else { - $totalissues = $biblioitem->totalissues + $increase; + $totalissues = $current_issues + $increase; } return 0 if $current_issues == $totalissues; # No need to update if no changes diff --git a/C4/Circulation.pm b/C4/Circulation.pm index bf93c32a59..f9cf48a605 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -4442,7 +4442,7 @@ sub ProcessOfflineOperation { if ( $operation->{action} eq 'return' ) { $report = ProcessOfflineReturn($operation); } elsif ( $operation->{action} eq 'issue' ) { - $report = ProcessOfflineIssue($operation); + ($report) = ProcessOfflineIssue($operation); } elsif ( $operation->{action} eq 'payment' ) { $report = ProcessOfflinePayment($operation); } @@ -4513,15 +4513,15 @@ sub ProcessOfflineIssue { $operation->{timestamp}, ); } - AddIssue( + my $checkout = AddIssue( $patron, - $operation->{'barcode'}, - undef, + $operation->{barcode}, + $operation->{due_date}, undef, $operation->{timestamp}, undef, ); - return "Success."; + return ( "Success.", $checkout ); } else { return "Borrower not found."; } diff --git a/C4/ClassSplitRoutine/LCC.pm b/C4/ClassSplitRoutine/LCC.pm index 12901ba3e3..a2ee632960 100644 --- a/C4/ClassSplitRoutine/LCC.pm +++ b/C4/ClassSplitRoutine/LCC.pm @@ -46,7 +46,7 @@ sub split_callnumber { # lccn examples: 'HE8700.7 .P6T44 1983', 'BS2545.E8 H39 1996'; my @lines = Library::CallNumber::LC->new($cn_item)->components(); unless ( scalar @lines && defined $lines[0] ) { - Koha::Logger->get->debug( sprintf( 'regexp failed to match string: %s', $cn_item ) ); + Koha::Logger->get->debug( sprintf( 'regexp failed to match string: %s', $cn_item // q{} ) ); @lines = $cn_item; # if no match, just use the whole string. } my $LastPiece = pop @lines; diff --git a/C4/Form/MessagingPreferences.pm b/C4/Form/MessagingPreferences.pm index 88c8e08fe1..36b0979099 100644 --- a/C4/Form/MessagingPreferences.pm +++ b/C4/Form/MessagingPreferences.pm @@ -148,6 +148,51 @@ PREF: foreach my $option (@$messaging_options) { $template->param( messaging_preferences => $messaging_options ); } +=head2 restore_form_values + + C4::Form::MessagingPreferences::restore_form_values( $input, $template ); + +Restores patron message preferences if error occurs while creating a patron. + +C<$input> is the CGI query object. + +C<$template> is the Template::Toolkit object for the response. + +=cut + +sub restore_form_values { + my ( $input, $template ) = @_; + my $messaging_options = C4::Members::Messaging::GetMessagingOptions(); + foreach my $option (@$messaging_options) { + $option->{ $option->{'message_name'} } = 1; + + my $message_attribute_id = $option->{'message_attribute_id'}; + if ( $option->{'takes_days'} ) { + my $selected_value = $input->param( $message_attribute_id . '-DAYS' ); + my $days_in_advance = $selected_value ? $selected_value : 0; + $option->{days_in_advance} = $days_in_advance; + @{ $option->{'select_days'} } = map { + { + day => $_, + selected => $_ == $days_in_advance + } + } ( 0 .. MAX_DAYS_IN_ADVANCE ); + } + + my @transport_types = $input->multi_param($message_attribute_id); + foreach my $transport_type (@transport_types) { + $option->{ 'transports_' . $transport_type } = 1; + } + + if ( $option->{'has_digest'} ) { + if ( List::Util::first { $_ == $message_attribute_id } $input->multi_param('digest') ) { + $option->{'digest'} = 1; + } + } + } + $template->param( messaging_preferences => $messaging_options ); +} + =head1 TODO =over 4 diff --git a/C4/Items.pm b/C4/Items.pm index 7f9f3fccdc..2c22518dc5 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -1732,7 +1732,17 @@ sub ToggleNewStatus { $item->$field($value); push @{ $report->{$itemnumber} }, $substitution; } - $item->store unless $report_only; + unless ($report_only) { + try { + $item->store; + } catch { + push @{ $report->{$itemnumber} }, { + field => 'ERROR', + error => 1, + value => $_->error, + } + } + } } } diff --git a/C4/Koha.pm b/C4/Koha.pm index 13e7a5da7d..bee096db9f 100644 --- a/C4/Koha.pm +++ b/C4/Koha.pm @@ -513,7 +513,7 @@ sub GetAuthorisedValues { my $opac = shift ? 1 : 0; # normalise to be safe # Is this cached already? - my $branch_limit = C4::Context->userenv ? C4::Context->userenv->{"branch"} : ""; + my $branch_limit = C4::Context::mybranch(); my $cache_key = "AuthorisedValues-$category-$opac-$branch_limit"; my $cache = Koha::Caches->get_instance(); my $result = $cache->get_from_cache($cache_key); diff --git a/C4/Labels/Label.pm b/C4/Labels/Label.pm index 842cfb051a..dd289083ee 100644 --- a/C4/Labels/Label.pm +++ b/C4/Labels/Label.pm @@ -385,8 +385,12 @@ sub draw_label_text { my $font = $self->{'font'}; my $item = _get_label_item( $self->{'item_number'} ); my $label_fields = _get_text_fields( $self->{'format_string'} ); - my $biblio = Koha::Biblios->find( $item->{biblionumber} ); - my $record = $biblio->metadata->record; + my $biblio = Koha::Biblios->find( $item->{'biblionumber'} ); + my $record; + + if ( defined $biblio ) { + $record = $biblio->metadata->record; + } # FIXME - returns all items, so you can't get data from an embedded holdings field. # TODO - add a GetMarcBiblio1item(bibnum,itemnum) or a GetMarcItem(itemnum). diff --git a/C4/SIP/ILS/Transaction/Checkout.pm b/C4/SIP/ILS/Transaction/Checkout.pm index 247ba86ca3..4909400493 100644 --- a/C4/SIP/ILS/Transaction/Checkout.pm +++ b/C4/SIP/ILS/Transaction/Checkout.pm @@ -156,13 +156,15 @@ sub do_checkout { if ($no_block_due_date) { $overridden_duedate = $no_block_due_date; - ProcessOfflineIssue( + my ( $msg, $checkout ) = ProcessOfflineIssue( { cardnumber => $patron->cardnumber, barcode => $barcode, - timestamp => $no_block_due_date, + due_date => $no_block_due_date, + timestamp => dt_from_string, } ); + $self->{due} = $self->duedatefromissue( $checkout, $itemnumber ); } else { # can issue diff --git a/C4/Scrubber.pm b/C4/Scrubber.pm index f5201418e7..40c0bee3dc 100644 --- a/C4/Scrubber.pm +++ b/C4/Scrubber.pm @@ -29,12 +29,13 @@ use C4::Context; my %scrubbertypes = ( default => {}, # place holder, default settings are below as fallbacks in call to constructor comment => { allow => [qw( br b i em big small strong )], }, - note => { allow => [qw[ br b i em big small strong u hr span div p ]] }, + note => { allow => [qw[ br b i em big small strong u hr span div p ol ul li dl dt dd ]] }, ); sub new { shift; # ignore our class we are wrapper my $type = (@_) ? shift : 'default'; + $type = 'default' if !defined $type; if ( !exists $scrubbertypes{$type} ) { croak "New called with unrecognized type '$type'"; } @@ -44,7 +45,6 @@ sub new { rules => exists $settings->{rules} ? $settings->{rules} : [], default => exists $settings->{default} ? $settings->{default} : [ 0 => { '*' => 0 } ], comment => exists $settings->{comment} ? $settings->{comment} : 0, - note => exists $settings->{note} ? $settings->{note} : 0, process => 0, ); return $scrubber; diff --git a/C4/Search.pm b/C4/Search.pm index 08903e7fc5..bf0a485286 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -40,6 +40,8 @@ use URI::Escape; use Business::ISBN; use MARC::Record; use MARC::Field; +use POSIX qw(setlocale LC_COLLATE); +use Unicode::Collate::Locale; our ( @ISA, @EXPORT_OK ); @@ -291,6 +293,40 @@ See verbose embedded documentation. =cut +=head2 _sort_facets_zebra + + my $sorted_facets = _sort_facets_zebra($facets, $locale); + +Sorts facets using a configurable locale for Zebra search engine. + +=cut + +sub _sort_facets_zebra { + my ( $facets, $locale ) = @_; + + if ( !$locale ) { + + # Get locale from system preference, falling back to system LC_COLLATE + $locale = C4::Context->preference('FacetSortingLocale') || 'default'; + if ( $locale eq 'default' || !$locale ) { + + #NOTE: When setlocale is run with only the 1st parameter, it is a "get" not a "set" function. + $locale = setlocale(LC_COLLATE) || 'default'; + } + } + + my $collator = Unicode::Collate::Locale->new( locale => $locale ); + if ( $collator && $facets ) { + my @sorted_facets = sort { $collator->cmp( $a->{facet_label_value}, $b->{facet_label_value} ) } @{$facets}; + if (@sorted_facets) { + return \@sorted_facets; + } + } + + #NOTE: If there was a problem, at least return the not sorted facets + return $facets; +} + sub getRecords { my ( $koha_query, $simple_query, $sort_by_ref, $servers_ref, @@ -554,8 +590,10 @@ sub getRecords { if (@facets_loop) { foreach my $f (@facets_loop) { if ( C4::Context->preference('FacetOrder') eq 'Alphabetical' ) { - $f->{facets} = - [ sort { uc( $a->{facet_label_value} ) cmp uc( $b->{facet_label_value} ) } @{ $f->{facets} } ]; + my $sorted_facets = _sort_facets_zebra( $f->{facets} ); + if ($sorted_facets) { + $f->{facets} = $sorted_facets; + } } } } diff --git a/Koha.pm b/Koha.pm index 926325f941..2ba56e0ae1 100644 --- a/Koha.pm +++ b/Koha.pm @@ -29,7 +29,7 @@ use vars qw{ $VERSION }; # - #4 : the developer version. The 4th number is the database subversion. # used by developers when the database changes. updatedatabase take care of the changes itself # and is automatically called by Auth.pm when needed. -$VERSION = "25.06.00.000"; +$VERSION = "25.06.00.005"; sub version { return $VERSION; diff --git a/Koha/Acquisition/Order/Claims.pm b/Koha/Acquisition/Order/Claims.pm index eef991990e..7cee67ff75 100644 --- a/Koha/Acquisition/Order/Claims.pm +++ b/Koha/Acquisition/Order/Claims.pm @@ -25,7 +25,7 @@ use base qw(Koha::Objects); =head1 NAME -Koha::Cities - Koha Claim Object set class +Koha::Acquisition::Order::Claims - Koha Claims Object set class =head1 API diff --git a/Koha/BackgroundJob/BatchUpdateItem.pm b/Koha/BackgroundJob/BatchUpdateItem.pm index 1158efd568..75250d6877 100644 --- a/Koha/BackgroundJob/BatchUpdateItem.pm +++ b/Koha/BackgroundJob/BatchUpdateItem.pm @@ -113,6 +113,7 @@ sub process { callback => sub { $self->step; }, } ); + $report->{errors} = $results->{errors}; $report->{modified_itemnumbers} = $results->{modified_itemnumbers}; $report->{modified_fields} = $results->{modified_fields}; } catch { @@ -123,7 +124,6 @@ sub process { my $data = $self->decoded_data; $data->{report} = $report; - $self->finish($data); } diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index 0df2b489a7..4c88bcd8a5 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -1921,164 +1921,195 @@ sub generate_marc_host_field { my $marcflavour = C4::Context->preference('marcflavour'); my $marc_host = $self->metadata->record; - my %sfd; + + my @sfd; my $host_field; my $link_field; if ( $marcflavour eq 'MARC21' ) { - # Author - if ( $host_field = $marc_host->field('100') || $marc_host->field('110') || $marc_host->field('111') ) { - my $s = $host_field->as_string('ab'); - if ($s) { - $sfd{a} = $s; + # Attempt to clone the main entry (100, 110, or 111) + my $main_entry = $marc_host->field('100') || $marc_host->field('110') || $marc_host->field('111'); + $main_entry = $main_entry ? $main_entry->clone : undef; + + # Clean unwanted subfields based on tag type + if ($main_entry) { + if ( $main_entry->tag eq '111' ) { + $main_entry->delete_subfield( code => qr/[94j]/ ); + } else { + $main_entry->delete_subfield( code => qr/[94e]/ ); } } - # Edition - if ( $host_field = $marc_host->field('250') ) { - my $s = $host_field->as_string('ab'); + # Construct subfield 7 from leader and main entry tag + my $s7 = "nn" . substr( $marc_host->leader, 6, 2 ); + if ($main_entry) { + my $c1 = 'n'; + if ( $main_entry->tag =~ /^1[01]/ ) { + $c1 = $main_entry->indicator('1'); + $c1 = $main_entry->tag eq '100' ? 1 : 2 unless $c1 =~ /\d/; + } + my $c0 = + ( $main_entry->tag eq '100' ) ? 'p' + : ( $main_entry->tag eq '110' ) ? 'c' + : ( $main_entry->tag eq '111' ) ? 'm' + : 'u'; + substr( $s7, 0, 2, $c0 . $c1 ); + } + push @sfd, ( '7' => $s7 ); + + # Subfield a - cleaned main entry string + if ($main_entry) { + my $a = $main_entry->as_string; + $a =~ s/\.$// unless $a =~ /\b[a-z]{1,2}\.$/i; + push @sfd, ( 'a' => $a ); + } + + # Subfield t - title from 245, cleaned + if ( my $f245 = $marc_host->field('245') ) { + my $f245c = $f245->clone; + $f245c->delete_subfield( code => 'c' ); + my $t = $f245c->as_string; + $t =~ s/[\s\/\\.]+$//; + my $nonfiling = $f245c->indicator('2') // 0; + $nonfiling = 0 unless $nonfiling =~ /^\d+$/; + $t = ucfirst substr( $t, $nonfiling ); + push @sfd, ( 't' => $t ); + } + + # Subfield b - edition from 250 + if ( my $f250 = $marc_host->field('250') ) { + my $b = $f250->as_string; + $b =~ s/\.$//; + if ($b) { + push @sfd, ( 'b' => $b ); + } + } + + # Subfield s - uniform title from 240 + if ( my $f240 = $marc_host->field('240') ) { + my $s = $f240->as_string('a'); if ($s) { - $sfd{b} = $s; + push @sfd, ( 's' => $s ); } } - # Publication + # Subfield d - publication info from 264/260 + my $d; my @publication_fields = $marc_host->field('264'); @publication_fields = $marc_host->field('260') unless (@publication_fields); my $index = 0; - for my $host_field (@publication_fields) { + for my $publication_field (@publication_fields) { # Use first entry unless we find a preferred indicator1 = 3 if ( $index == 0 ) { - my $s = $host_field->as_string('abc'); + my $s = $publication_field->as_string('abc'); + $s =~ s/\.$//; if ($s) { - $sfd{d} = $s; + $d = $s; } $index++; } - if ( $host_field->indicator(1) && ( $host_field->indicator(1) eq '3' ) ) { - my $s = $host_field->as_string('abc'); + if ( $publication_field->indicator(1) && ( $publication_field->indicator(1) eq '3' ) ) { + my $s = $publication_field->as_string('abc'); + $s =~ s/\.$//; if ($s) { - $sfd{d} = $s; + $d = $s; } last; } } - - # Uniform title - if ( $host_field = $marc_host->field('240') ) { - my $s = $host_field->as_string('a'); - if ($s) { - $sfd{s} = $s; - } + push @sfd, ( d => $d ) if $d; + + # Subfield k - host info from 800-830 fields + for my $f ( $marc_host->field('8[013][01]') ) { + my $k = $f->as_string('abcdnjltnp'); + $k .= ', ISSN ' . $f->subfield('x') if $f->subfield('x'); + $k .= ' ; ' . $f->subfield('v') if $f->subfield('v'); + push @sfd, ( 'k' => $k ); } - # Title - if ( $host_field = $marc_host->field('245') ) { - my $s = $host_field->as_string('abnp'); - if ($s) { - $sfd{t} = $s; - } + # Subfield x - ISSN from 022 + for my $f ( $marc_host->field('022') ) { + push @sfd, ( 'x' => $f->subfield('a') ) if $f->subfield('a'); } - # ISSN - if ( $host_field = $marc_host->field('022') ) { - my $s = $host_field->as_string('a'); - if ($s) { - $sfd{x} = $s; - } + # Subfield z - ISBN from 020 + for my $f ( $marc_host->field('020') ) { + push @sfd, ( 'z' => $f->subfield('a') ) if $f->subfield('a'); } - # ISBN - if ( $host_field = $marc_host->field('020') ) { - my $s = $host_field->as_string('a'); - if ($s) { - $sfd{z} = $s; + # Subfield w - control number (001 and optionally 003) + if ( C4::Context->preference('UseControlNumber') ) { + if ( my $f001 = $marc_host->field('001') ) { + my $w = $f001->data; + if ( my $f003 = $marc_host->field('003') ) { + $w = '(' . $f003->data . ')' . $w; + } + push @sfd, ( 'w' => $w ); } } - if ( C4::Context->preference('UseControlNumber') ) { - # Control number - if ( $host_field = $marc_host->field('001') ) { - $sfd{w} = $host_field->data(); - } + # Construct 773 link field + $link_field = MARC::Field->new( 773, '0', ' ', @sfd ); - # Control number identifier - if ( $host_field = $marc_host->field('003') ) { - $sfd{w} = '(' . $host_field->data() . ')' . $sfd{w}; - } - } - $link_field = MARC::Field->new( 773, '0', ' ', %sfd ); } elsif ( $marcflavour eq 'UNIMARC' ) { - # Author + # Author (700/710/720) if ( $host_field = $marc_host->field('700') || $marc_host->field('710') || $marc_host->field('720') ) { my $s = $host_field->as_string('ab'); - if ($s) { - $sfd{a} = $s; - } + push @sfd, ( 'a' => $s ) if $s; } - # Place of publication + # Title (200) + if ( $host_field = $marc_host->field('200') ) { + my $s = $host_field->as_string('a'); + push @sfd, ( 't' => $s ) if $s; + } + + # Place of publication (210$a) if ( $host_field = $marc_host->field('210') ) { my $s = $host_field->as_string('a'); - if ($s) { - $sfd{c} = $s; - } + push @sfd, ( 'c' => $s ) if $s; } - # Date of publication + # Date of publication (210$d) if ( $host_field = $marc_host->field('210') ) { my $s = $host_field->as_string('d'); - if ($s) { - $sfd{d} = $s; - } + push @sfd, ( 'd' => $s ) if $s; } - # Edition statement + # Edition statement (205) if ( $host_field = $marc_host->field('205') ) { - my $s = $host_field->as_string(); - if ($s) { - $sfd{e} = $s; - } + my $s = $host_field->as_string; + push @sfd, ( 'e' => $s ) if $s; } - # Title - if ( $host_field = $marc_host->field('200') ) { - my $s = $host_field->as_string('a'); - if ($s) { - $sfd{t} = $s; - } - } - - #URL + # URL (856$u) if ( $host_field = $marc_host->field('856') ) { my $s = $host_field->as_string('u'); - if ($s) { - $sfd{u} = $s; - } + push @sfd, ( u => $s ) if ($s); } - # ISSN + # ISSN (011$a) if ( $host_field = $marc_host->field('011') ) { my $s = $host_field->as_string('a'); - if ($s) { - $sfd{x} = $s; - } + push @sfd, ( x => $s ) if ($s); } - # ISBN + # ISBN (010$a) if ( $host_field = $marc_host->field('010') ) { my $s = $host_field->as_string('a'); - if ($s) { - $sfd{y} = $s; - } + push @sfd, ( y => $s ) if ($s); } + + # Control number (001) if ( $host_field = $marc_host->field('001') ) { - $sfd{0} = $host_field->data(); + push @sfd, ( 0 => $host_field->data() ); } - $link_field = MARC::Field->new( 461, '0', ' ', %sfd ); + + # Construct 461 link field + $link_field = MARC::Field->new( 461, '0', ' ', @sfd ); } return $link_field; diff --git a/Koha/CookieManager.pm b/Koha/CookieManager.pm index 3b655fa12c..2c5ae33516 100644 --- a/Koha/CookieManager.pm +++ b/Koha/CookieManager.pm @@ -25,7 +25,28 @@ use CGI::Cookie; use C4::Context; -use constant DENY_LIST_VAR => 'do_not_remove_cookie'; +# The cookies on the following list are removed unless koha-conf.xml indicates otherwise. +# koha-conf.xml may also contain additional cookies to be removed. +# Not including here: always_show_holds, catalogue_editor_, issues-table-load-immediately-circulation, +# and ItemEditorSessionTemplateId. +# TODO Not sure about branch (rotatingcollections), patronSessionConfirmation (circulation.pl) +use constant MANAGED_COOKIE_PREFIXES => qw{ + bib_list + CGISESSID + holdfor holdforclub + intranet_bib_list + JWT + KohaOpacLanguage + LastCreatedItem + marctagstructure_selectdisplay + search_path_code + searchToOrder +}; +use constant PATH_EXCEPTIONS => { + always_show_holds => '/cgi-bin/koha/reserve', +}; +use constant KEEP_COOKIE_CONF_VAR => 'do_not_remove_cookie'; +use constant REMOVE_COOKIE_CONF_VAR => 'remove_cookie'; our $cookies; @@ -41,18 +62,22 @@ Koha::CookieManager - Object for unified handling of cookies in Koha # Replace cookies $cookie_list = $mgr->replace_in_list( [ $cookie1, $cookie2_old ], $cookie2_new ); - # Clear cookies (governed by deny list entries in koha-conf) + # Clear cookies $cookie_list = $mgr->clear_unless( $cookie1, $cookie2, $cookie3_name ); =head1 DESCRIPTION -The current object allows you to clear cookies in a list based on the deny list -in koha-conf.xml. It also offers a method to replace the old version of a cookie +The current object allows you to remove cookies on the hardcoded list +in this module, refined by 'keep' or 'remove' entries in koha-conf.xml. +Note that a keep entry overrules a remove. + +This module also offers a method to replace the old version of a cookie by a new one. -It could be extended by (gradually) routing cookie creation through it in order -to consistently fill cookie parameters like httponly, secure and samesite flag, -etc. And could serve to register all our cookies in a central location. +The module could be extended by (gradually) routing cookie creation +through it in order to consistently fill cookie parameters like httponly, +secure and samesite flag, etc. And could serve to register all our cookies +in a central location. =head1 METHODS @@ -64,11 +89,15 @@ etc. And could serve to register all our cookies in a central location. sub new { my ( $class, $params ) = @_; - my $self = bless $params // {}, $class; - my $denied = C4::Context->config(DENY_LIST_VAR) || []; # expecting scalar or arrayref - $denied = [$denied] if ref($denied) eq q{}; - $self->{_remove_unless} = { map { $_ => 1 } @$denied }; - $self->{_secure} = C4::Context->https_enabled; + my $self = bless $params // {}, $class; + + # Get keep and remove list from koha-conf (scalar or arrayref) + my $keep_list = C4::Context->config(KEEP_COOKIE_CONF_VAR) || []; + $self->{_keep_list} = ref($keep_list) ? $keep_list : [$keep_list]; + my $remove_list = C4::Context->config(REMOVE_COOKIE_CONF_VAR) || []; + $self->{_remove_list} = ref($remove_list) ? $remove_list : [$remove_list]; + + $self->{_secure} = C4::Context->https_enabled; return $self; } @@ -80,9 +109,9 @@ sub new { Note: in the example above $query->cookie is a list of cookie names as returned by the CGI object. - Returns an arrayref of cookie objects: empty, expired cookies for those passed - by name or objects that are not on the deny list, together with the remaining - (untouched) cookie objects that are on the deny list. + Returns an arrayref of cookie objects: empty, expired cookies for + cookies on the remove list, together with the remaining (untouched) + cookie objects. =cut @@ -102,17 +131,15 @@ sub clear_unless { } next if !$name; - if ( $self->_should_be_cleared($name) ) { + if ( $self->_should_be_removed($name) ) { next if $seen->{$name}; - push @rv, CGI::Cookie->new( - - # -expires explicitly omitted to create shortlived 'session' cookie - # -HttpOnly explicitly set to 0: not really needed here for the - # cleared httponly cookies, while the js cookies should be 0 - -name => $name, -value => q{}, -HttpOnly => 0, - $self->{_secure} ? ( -secure => 1 ) : (), - ); $seen->{$name} = 1; # prevent duplicates + if ($type) { + $c->max_age(0); + push @rv, _correct_path($c); + } else { + push @rv, _correct_path( CGI::Cookie->new( -name => $name, -value => q{}, '-max-age' => 0 ) ); + } } elsif ( $type eq 'CGI::Cookie' ) { # keep the last occurrence @rv = @{ $self->replace_in_list( \@rv, $c ) }; } @@ -120,22 +147,6 @@ sub clear_unless { return \@rv; } -sub _should_be_cleared { # when it is not on the deny list in koha-conf - my ( $self, $name ) = @_; - - return if $self->{_remove_unless}->{$name}; # exact match - - # Now try the entries as regex - foreach my $k ( keys %{ $self->{_remove_unless} } ) { - my $reg = $self->{_remove_unless}->{$k}; - - # The entry in koha-conf should match the complete string - # So adding a ^ and $ - return if $name =~ qr/^${k}$/; - } - return 1; -} - =head2 replace_in_list $list2 = $mgr->replace_in_list( $list1, $cookie ); @@ -162,7 +173,44 @@ sub replace_in_list { return \@result; } -=head1 INTERNAL ROUTINES +# INTERNAL ROUTINES + +sub _should_be_removed { + my ( $self, $name ) = @_; + + # Is this a controlled cookie? Or is it added as 'keep' or 'remove' in koha-conf.xml? + # The conf entries are treated as prefix (no longer as regex). + return unless grep { $name =~ /^$_/ } MANAGED_COOKIE_PREFIXES(), @{ $self->{_remove_list} }; + return !grep { $name =~ /^$_/ } @{ $self->{_keep_list} }; +} + +sub _correct_path { + my $cookie_object = shift; + my $path = PATH_EXCEPTIONS->{ $cookie_object->name } or return $cookie_object; + $cookie_object->path($path); + return $cookie_object; +} + +=head1 ADDITIONAL COMMENTS + + How do the keep or remove lines in koha-conf.xml work? + + some_cookie + The name some_cookie should refer here to a cookie that is on the + hardcoded list in this module. If you do not want it to be cleared + (removed) on logout, include this line. + You might want to do this e.g. for KohaOpacLanguage. + + another_cookie + The name another_cookie refers here to a cookie that is not on the + hardcoded list but you want this cookie to be cleared/removed on logout. + It could be a custom cookie. + + Note that both directives use the cookie name as a prefix. So if you + add a remove line for cookie1, it also affects cookie12, etc. + Since a keep line overrules a remove line, this allows you to add + lines for removing cookie1 and not removing cookie12 in order to + remove cookie1, cookie11, cookie13 but not cookie12, etc. =cut diff --git a/Koha/Course.pm b/Koha/Course.pm index 6b67a2b592..e4b800f043 100644 --- a/Koha/Course.pm +++ b/Koha/Course.pm @@ -2,18 +2,18 @@ package Koha::Course; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Course/Instructor.pm b/Koha/Course/Instructor.pm index 4b6f8a262d..da9864fe17 100644 --- a/Koha/Course/Instructor.pm +++ b/Koha/Course/Instructor.pm @@ -2,18 +2,18 @@ package Koha::Course::Instructor; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Course/Instructors.pm b/Koha/Course/Instructors.pm index 82a0191b34..95e13bb9c3 100644 --- a/Koha/Course/Instructors.pm +++ b/Koha/Course/Instructors.pm @@ -2,18 +2,18 @@ package Koha::Course::Instructors; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Course/Item.pm b/Koha/Course/Item.pm index d13be0ba55..6d6f3b626a 100644 --- a/Koha/Course/Item.pm +++ b/Koha/Course/Item.pm @@ -2,18 +2,18 @@ package Koha::Course::Item; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Course/Items.pm b/Koha/Course/Items.pm index f563998515..b6feda4f77 100644 --- a/Koha/Course/Items.pm +++ b/Koha/Course/Items.pm @@ -2,18 +2,18 @@ package Koha::Course::Items; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Course/Reserve.pm b/Koha/Course/Reserve.pm index 6493ba90a3..0fb1906c9b 100644 --- a/Koha/Course/Reserve.pm +++ b/Koha/Course/Reserve.pm @@ -2,18 +2,18 @@ package Koha::Course::Reserve; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Course/Reserves.pm b/Koha/Course/Reserves.pm index b824a78da2..5bd38a2fe7 100644 --- a/Koha/Course/Reserves.pm +++ b/Koha/Course/Reserves.pm @@ -2,18 +2,18 @@ package Koha::Course::Reserves; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Courses.pm b/Koha/Courses.pm index 6a3f396daa..7604deab0b 100644 --- a/Koha/Courses.pm +++ b/Koha/Courses.pm @@ -2,18 +2,18 @@ package Koha::Courses; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/CoverImages.pm b/Koha/CoverImages.pm index 774d36ada8..26e9fc5e5e 100644 --- a/Koha/CoverImages.pm +++ b/Koha/CoverImages.pm @@ -25,7 +25,7 @@ use base qw(Koha::Objects); =head1 NAME -Koha::Cities - Koha CoverImage Object set class +Koha::CoverImages - Koha CoverImage Object set class =head1 API diff --git a/Koha/Devel/Files.pm b/Koha/Devel/Files.pm new file mode 100644 index 0000000000..df1bba620b --- /dev/null +++ b/Koha/Devel/Files.pm @@ -0,0 +1,192 @@ +package Koha::Devel::Files; + +use Modern::Perl; +our ( @ISA, @EXPORT_OK ); + +=head1 NAME + +Koha::Devel::Files - A utility module for managing and filtering file lists in the Koha codebase + +=head1 SYNOPSIS + + use Koha::Devel::Files; + + my $file_manager = Koha::Devel::Files->new({ context => 'tidy' }); + + my @perl_files = $file_manager->ls_perl_files($git_range); + my @js_files = $file_manager->ls_js_files(); + my @tt_files = $file_manager->ls_tt_files(); + + my $filetype = $file_manager->get_filetype($filename); + +=head1 DESCRIPTION + +Koha::Devel::Files is a utility module designed to assist in managing and filtering lists of files in the Koha codebase. It provides methods to list Perl, JavaScript, and Template Toolkit files, with options to exclude specific files based on a given context. + +=head1 EXCEPTIONS + +The module defines a set of exceptions for different file types and contexts. These exceptions are used to exclude specific files or directories from the file listings. + +=cut + +my $exceptions = { + pl => { + tidy => [ + qw( + Koha/Schema/Result + Koha/Schema.pm + ) + ], + valid => [ + qw( + Koha/Account/Credit.pm + Koha/Account/Debit.pm + Koha/Old/Hold.pm + misc/translator/TmplTokenizer.pm + ) + ], + codespell => [ + qw( + installer/data/mysql/updatedatabase.pl + installer/data/mysql/update22to30.pl + installer/data/mysql/db_revs/241200035.pl + misc/cronjobs/build_browser_and_cloud.pl + ) + ], + }, + js => { + tidy => [ + qw( + koha-tmpl/intranet-tmpl/lib + koha-tmpl/intranet-tmpl/js/Gettext.js + koha-tmpl/opac-tmpl/lib + Koha/ILL/Backend/ + ) + ], + codespell => [ + qw( + koha-tmpl/intranet-tmpl/lib + koha-tmpl/intranet-tmpl/js/Gettext.js + koha-tmpl/opac-tmpl/lib + koha-tmpl/opac-tmpl/bootstrap/js/Gettext.js + ) + ], + }, + tt => { + tidy => [ + qw( + Koha/ILL/Backend/ + *doc-head-open.inc + misc/cronjobs/rss + ) + ], + codespell => [], + }, +}; + +=head1 METHODS + +=cut + +=head2 new + + my $file_manager = Koha::Devel::Files->new({ context => 'tidy' }); + +Creates a new instance of Koha::Devel::Files. The constructor accepts a hash reference with a 'context' key, which specifies the context for file exclusions. + +=cut + +sub new { + my ( $class, $args ) = @_; + my $self = { context => $args->{context} }; + bless $self, $class; + return $self; +} + +=head2 build_git_exclude + + my $exclude_pattern = $file_manager->build_git_exclude($filetype); + +Builds a Git exclude pattern for a given file type based on the context provided during object creation. + +=cut + +sub build_git_exclude { + my ( $self, $filetype ) = @_; + return $self->{context} && exists $exceptions->{$filetype}->{ $self->{context} } + ? join( " ", map( "':(exclude)$_'", @{ $exceptions->{$filetype}->{ $self->{context} } } ) ) + : q{}; +} + +=head2 ls_perl_files + + my @perl_files = $file_manager->ls_perl_files($git_range); + +Lists Perl files (with extensions .pl, .PL, .pm, .t) that have been modified within a specified Git range. If no range is provided, it lists all Perl files, excluding those specified in the exceptions. + +=cut + +sub ls_perl_files { + my ($self) = @_; + my $cmd = sprintf q{git ls-files '*.pl' '*.PL' '*.pm' '*.t' svc opac/svc debian/build-git-snapshot %s}, + $self->build_git_exclude('pl'); + my @files = qx{$cmd}; + chomp for @files; + return @files; +} + +=head2 ls_js_files + + my @js_files = $file_manager->ls_js_files(); + +Lists JavaScript and TypeScript files (with extensions .js, .ts, .vue) in the repository, excluding those specified in the exceptions. + +=cut + +sub ls_js_files { + my ($self) = @_; + my $cmd = sprintf q{git ls-files '*.js' '*.ts' '*.vue' %s}, $self->build_git_exclude('js'); + my @files = qx{$cmd}; + chomp for @files; + return @files; +} + +=head2 ls_tt_files + + my @tt_files = $file_manager->ls_tt_files(); + +Lists Template Toolkit files (with extensions .tt, .inc) in the repository, excluding those specified in the exceptions. + +=cut + +sub ls_tt_files { + my ($self) = @_; + my $cmd = sprintf q{git ls-files '*.tt' '*.inc' %s}, $self->build_git_exclude('tt'); + my @files = qx{$cmd}; + chomp for @files; + return @files; +} + +=head2 get_filetype + + my $filetype = $file_manager->get_filetype($filename); + +Determines the file type of a given file based on its extension or path. Returns 'pl' for Perl files, 'js' for JavaScript/TypeScript files, and 'tt' for Template Toolkit files. Dies with an error message if the file type cannot be determined. + +=cut + +sub get_filetype { + my ( $self, $file ) = @_; + return 'pl' if $file =~ m{^svc} || $file =~ m{^opac/svc}; + return 'pl' if $file =~ m{\.pl$} || $file =~ m{\.pm} || $file =~ m{\.t$}; + return 'pl' if $file =~ m{\.PL$}; + return 'pl' if $file =~ m{debian/build-git-snapshot}; + + return 'js' if $file =~ m{\.js$} || $file =~ m{\.ts$} || $file =~ m{\.vue$}; + + return 'tt' if $file =~ m{\.inc$} || $file =~ m{\.tt$}; + + die sprintf 'Cannot guess filetype for %s', $file; +} + +1; diff --git a/Koha/Encryption.pm b/Koha/Encryption.pm index b18f75a9d4..4cecb6e282 100644 --- a/Koha/Encryption.pm +++ b/Koha/Encryption.pm @@ -61,8 +61,9 @@ sub new { ); } return $class->SUPER::new( - -key => $encryption_key, - -cipher => 'Cipher::AES' + -key => $encryption_key, + -cipher => 'Cipher::AES', + -nodeprecate => 1, ); } diff --git a/Koha/Exceptions/MarcOverlayRule.pm b/Koha/Exceptions/MarcOverlayRule.pm index d2e44970af..2cedb3526a 100644 --- a/Koha/Exceptions/MarcOverlayRule.pm +++ b/Koha/Exceptions/MarcOverlayRule.pm @@ -2,18 +2,18 @@ package Koha::Exceptions::MarcOverlayRule; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Filter/MARC/TrimFields.pm b/Koha/Filter/MARC/TrimFields.pm index 99a5f0dfa3..00244cab29 100644 --- a/Koha/Filter/MARC/TrimFields.pm +++ b/Koha/Filter/MARC/TrimFields.pm @@ -60,9 +60,15 @@ sub filter { my $value = $subfield->[1]; $value =~ s/[\n\r]+/ /g; $value =~ s/^\s+|\s+$//g; - $field->add_subfields( $key => $value ); # add subfield to the end of the subfield list - $field->delete_subfield( pos => 0 ); # delete the subfield at the top of the subfield list + $field->add_subfields( $key => $value ) + if $value ne q{} + ; # add subfield to the end of the subfield list, but only if there is still a non empty value there + $field->delete_subfield( pos => 0 ); # delete the subfield at the top of the subfield list } + + # if it happed that all existing subfields had whitespaces only, + # the field would be empty now and should be removed from the record + $record->delete_fields($field) unless scalar( $field->subfields ); } } return $record; diff --git a/Koha/Hold.pm b/Koha/Hold.pm index 8f0cd75ac2..59b498a7d2 100644 --- a/Koha/Hold.pm +++ b/Koha/Hold.pm @@ -972,6 +972,9 @@ sub store { } } } + if ( exists $updated_columns{branchcode} ) { + Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue->new->enqueue( { biblio_ids => [ $self->biblionumber ] } ); + } } $self = $self->SUPER::store; diff --git a/Koha/I18N.pm b/Koha/I18N.pm index c957e9df40..3fbbabe685 100644 --- a/Koha/I18N.pm +++ b/Koha/I18N.pm @@ -53,8 +53,51 @@ our @EXPORT = qw( N__np ); +our @EXPORT_OK = qw( + available_locales +); + our $textdomain = 'Koha'; +=head1 NAME + +Koha::I18N - Internationalization functions for Koha + +=head1 SYNOPSIS + + use Koha::I18N; + + # Basic translation functions + my $translated = __('Hello world'); + my $with_vars = __x('Hello {name}', name => 'World'); + my $plural = __n('one item', '{count} items', $count, count => $count); + + # Context-aware translations + my $context = __p('menu', 'File'); + + # Get available system locales (explicitly imported) + use Koha::I18N qw(available_locales); + my $locales = available_locales(); + +=head1 DESCRIPTION + +This module provides internationalization (i18n) functions for Koha using the +GNU gettext system. It handles locale setup, message translation, and provides +utility functions for working with system locales. + +The module automatically initializes the locale environment and provides a set +of translation functions that support variable substitution, plural forms, and +contextual translations. + +=head1 FUNCTIONS + +=head2 init + +Initializes the internationalization system by setting up locale environment +variables and configuring gettext. This is called automatically when needed. + +=cut + sub init { my $cache = Koha::Cache::Memory::Lite->get_instance(); my $cache_key = 'i18n:initialized'; @@ -92,6 +135,14 @@ sub init { } } +=head2 __ + + my $translated = __('Text to translate'); + +Basic translation function. Returns the translated text for the given message ID. + +=cut + sub __ { my ($msgid) = @_; @@ -100,6 +151,15 @@ sub __ { return _gettext( \&gettext, [$msgid] ); } +=head2 __x + + my $translated = __x('Hello {name}', name => 'World'); + +Translation with variable substitution. Variables in {brackets} are replaced +with the corresponding values from the provided hash. + +=cut + sub __x { my ( $msgid, %vars ) = @_; @@ -108,6 +168,14 @@ sub __x { return _gettext( \&gettext, [$msgid], %vars ); } +=head2 __n + + my $translated = __n('one item', '{count} items', $count); + +Plural-aware translation. Returns singular or plural form based on the count. + +=cut + sub __n { my ( $msgid, $msgid_plural, $count ) = @_; @@ -117,6 +185,14 @@ sub __n { return _gettext( \&ngettext, [ $msgid, $msgid_plural, $count ] ); } +=head2 __nx + + my $translated = __nx('one item', '{count} items', $count, count => $count); + +Plural-aware translation with variable substitution. + +=cut + sub __nx { my ( $msgid, $msgid_plural, $count, %vars ) = @_; @@ -126,10 +202,25 @@ sub __nx { return _gettext( \&ngettext, [ $msgid, $msgid_plural, $count ], %vars ); } +=head2 __xn + +Alias for __nx. + +=cut + sub __xn { return __nx(@_); } +=head2 __p + + my $translated = __p('context', 'Text to translate'); + +Context-aware translation. Allows the same text to be translated differently +based on context (e.g., 'File' in a menu vs 'File' as a document type). + +=cut + sub __p { my ( $msgctxt, $msgid ) = @_; @@ -139,6 +230,14 @@ sub __p { return _gettext( \&pgettext, [ $msgctxt, $msgid ] ); } +=head2 __px + + my $translated = __px('context', 'Hello {name}', name => 'World'); + +Context-aware translation with variable substitution. + +=cut + sub __px { my ( $msgctxt, $msgid, %vars ) = @_; @@ -148,6 +247,14 @@ sub __px { return _gettext( \&pgettext, [ $msgctxt, $msgid ], %vars ); } +=head2 __np + + my $translated = __np('context', 'one item', '{count} items', $count); + +Context-aware plural translation. + +=cut + sub __np { my ( $msgctxt, $msgid, $msgid_plural, $count ) = @_; @@ -158,6 +265,14 @@ sub __np { return _gettext( \&npgettext, [ $msgctxt, $msgid, $msgid_plural, $count ] ); } +=head2 __npx + + my $translated = __npx('context', 'one item', '{count} items', $count, count => $count); + +Context-aware plural translation with variable substitution. + +=cut + sub __npx { my ( $msgctxt, $msgid, $msgid_plural, $count, %vars ) = @_; @@ -168,18 +283,51 @@ sub __npx { return _gettext( \&npgettext, [ $msgctxt, $msgid, $msgid_plural, $count ], %vars ); } +=head2 N__ + + my $msgid = N__('Text for later translation'); + +No-operation translation marker. Returns the original text unchanged but marks +it for extraction by translation tools. + +=cut + sub N__ { return $_[0]; } +=head2 N__n + + my $msgid = N__n('singular', 'plural'); + +No-operation plural translation marker. + +=cut + sub N__n { return $_[0]; } +=head2 N__p + + my $msgid = N__p('context', 'Text for later translation'); + +No-operation context translation marker. + +=cut + sub N__p { return $_[1]; } +=head2 N__np + + my $msgid = N__np('context', 'singular', 'plural'); + +No-operation context plural translation marker. + +=cut + sub N__np { return $_[1]; } @@ -224,4 +372,118 @@ sub _expand { return $text; } +=head2 available_locales + + my $locales = Koha::I18N::available_locales(); + +Returns an arrayref of available system locales for use in system preferences. + +Each locale is a hashref with: + - C: The locale identifier (e.g., 'en_US.utf8', 'default') + - C: Human-readable description (e.g., 'English (United States) - en_US.utf8') + +Always includes 'default' as the first option. Additional locales are detected +from the system using C and filtered for UTF-8 locales. + +=cut + +sub available_locales { + my @available_locales = (); + + # Always include default option + push @available_locales, { + value => 'default', + text => 'Default Unicode collation' + }; + + # Get system locales using the same approach as init() + my @system_locales = grep { chomp; not( /^C/ || $_ eq 'POSIX' ) } qx/locale -a/; + + my @filtered_locales = (); + for my $locale (@system_locales) { + + # Filter for useful locales (UTF-8 ones and common patterns) + if ( $locale =~ /^[a-z]{2}_[A-Z]{2}\.utf8?$/i || $locale =~ /^[a-z]{2}_[A-Z]{2}$/i ) { + + # Create friendly display names + my $display_name = $locale; + if ( $locale =~ /^([a-z]{2})_([A-Z]{2})/ ) { + my %lang_names = ( + 'en' => 'English', + 'fr' => 'French', + 'de' => 'German', + 'es' => 'Spanish', + 'it' => 'Italian', + 'pt' => 'Portuguese', + 'nl' => 'Dutch', + 'pl' => 'Polish', + 'fi' => 'Finnish', + 'sv' => 'Swedish', + 'da' => 'Danish', + 'no' => 'Norwegian', + 'ru' => 'Russian', + 'ja' => 'Japanese', + 'zh' => 'Chinese', + 'ar' => 'Arabic', + 'hi' => 'Hindi' + ); + my %country_names = ( + 'US' => 'United States', + 'GB' => 'United Kingdom', + 'FR' => 'France', + 'DE' => 'Germany', + 'ES' => 'Spain', + 'IT' => 'Italy', + 'PT' => 'Portugal', + 'BR' => 'Brazil', + 'NL' => 'Netherlands', + 'PL' => 'Poland', + 'FI' => 'Finland', + 'SE' => 'Sweden', + 'DK' => 'Denmark', + 'NO' => 'Norway', + 'RU' => 'Russia', + 'JP' => 'Japan', + 'CN' => 'China', + 'TW' => 'Taiwan', + 'SA' => 'Saudi Arabia', + 'IN' => 'India' + ); + my $lang = $lang_names{$1} || uc($1); + my $country = $country_names{$2} || $2; + $display_name = "$lang ($country) - $locale"; + } + push @filtered_locales, { + value => $locale, + text => $display_name + }; + } + } + + # Sort locales by display name and add to available list + @filtered_locales = sort { $a->{text} cmp $b->{text} } @filtered_locales; + push @available_locales, @filtered_locales; + + return \@available_locales; +} + +=head1 AUTHOR + +Koha Development Team + +=head1 COPYRIGHT + +Copyright 2012-2014 BibLibre + +=head1 LICENSE + +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. + +=cut + 1; diff --git a/Koha/ILL/Backend/Standard.pm b/Koha/ILL/Backend/Standard.pm index 5962cd1765..444c0074d9 100644 --- a/Koha/ILL/Backend/Standard.pm +++ b/Koha/ILL/Backend/Standard.pm @@ -1058,8 +1058,6 @@ sub _openurl_to_ill { volume => 'volume', isbn => 'isbn', issn => 'issn', - rft_id => 'doi', - id => 'doi', doi => 'doi', year => 'year', title => 'title', @@ -1097,8 +1095,19 @@ sub _openurl_to_ill { # Otherwise, pass it through untransformed and maybe move it # to our custom parameters array if ( !exists $ignore->{$meta_key} ) { - push @{$custom_key}, $meta_key; - push @{$custom_value}, $params->{other}->{$meta_key}; + if ( $meta_key eq 'id' || $meta_key eq 'rft_id' ) { + if ( $params->{other}->{$meta_key} =~ /:/ ) { + my ( $k, $v ) = split /:/, $params->{other}->{$meta_key}, 2; + if ( defined $k && defined $v ) { + $return->{ lc $k } = $v; + } + } else { + $return->{doi} = $params->{other}->{$meta_key}; + } + } else { + push @{$custom_key}, $meta_key; + push @{$custom_value}, $params->{other}->{$meta_key}; + } } else { $return->{$meta_key} = $params->{other}->{$meta_key}; } diff --git a/Koha/ILL/Request.pm b/Koha/ILL/Request.pm index 9b151e3924..4c8453d4dd 100644 --- a/Koha/ILL/Request.pm +++ b/Koha/ILL/Request.pm @@ -1776,6 +1776,8 @@ sub send_patron_notice { ); my @transports = keys %{ $borrower_preferences->{transports} }; + return { result => { fail => [ 'email', 'sms' ], success => [] } } unless @transports; + # Notice should come from the library where the request was placed, # not the patrons home library my $branch = Koha::Libraries->find( $self->branchcode ); diff --git a/Koha/Import/OAI/Authorities.pm b/Koha/Import/OAI/Authorities.pm index cdff207854..9b78afefb4 100644 --- a/Koha/Import/OAI/Authorities.pm +++ b/Koha/Import/OAI/Authorities.pm @@ -13,6 +13,7 @@ package Koha::Import::OAI::Authorities; # 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; diff --git a/Koha/Import/OAI/Authority.pm b/Koha/Import/OAI/Authority.pm index f4e3a0d31f..965851d39c 100644 --- a/Koha/Import/OAI/Authority.pm +++ b/Koha/Import/OAI/Authority.pm @@ -13,6 +13,7 @@ package Koha::Import::OAI::Authority; # 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; diff --git a/Koha/Import/OAI/Biblio.pm b/Koha/Import/OAI/Biblio.pm index 42ad046e72..3478a348eb 100644 --- a/Koha/Import/OAI/Biblio.pm +++ b/Koha/Import/OAI/Biblio.pm @@ -13,6 +13,7 @@ package Koha::Import::OAI::Biblio; # 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; diff --git a/Koha/Import/OAI/Biblios.pm b/Koha/Import/OAI/Biblios.pm index 59ceba9cd3..4a7a04cf79 100644 --- a/Koha/Import/OAI/Biblios.pm +++ b/Koha/Import/OAI/Biblios.pm @@ -13,6 +13,7 @@ package Koha::Import::OAI::Biblios; # 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; diff --git a/Koha/Installer.pm b/Koha/Installer.pm index 235eac3247..48a50df2b6 100644 --- a/Koha/Installer.pm +++ b/Koha/Installer.pm @@ -29,7 +29,7 @@ sub needs_update { my $koha_version = Koha->version; my $code_version = TransformToNum($koha_version); - if ( $db_version == $code_version ) { + if ( $db_version && $db_version == $code_version ) { $needs_update = 0; } diff --git a/Koha/Item.pm b/Koha/Item.pm index 87e6dd8c31..eb36e62b06 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -188,6 +188,24 @@ sub store { } } + my $prevent_withdrawing_of = C4::Context->preference('PreventWithdrawingItemsStatus'); + my @statuses_to_prevent = defined $prevent_withdrawing_of ? split( ',', $prevent_withdrawing_of ) : (); + my $prevent_onloan = grep { $_ eq 'checkedout' } @statuses_to_prevent; + my $prevent_intransit = grep { $_ eq 'intransit' } @statuses_to_prevent; + + if ( exists $updated_columns{withdrawn} && $updated_columns{withdrawn} ) { + my $transfer = $pre_mod_item->get_transfer; + if ( $pre_mod_item->onloan && $prevent_onloan ) { + Koha::Exceptions::Item::Transfer::OnLoan->throw( error => "onloan_cannot_withdraw" ); + return $self->SUPER::store; + } + + if ( defined $transfer && $transfer->in_transit && $prevent_intransit ) { + Koha::Exceptions::Item::Transfer::InTransit->throw( error => "intransit_cannot_withdraw" ); + return $self->SUPER::store; + } + } + if ( exists $updated_columns{itemcallnumber} or exists $updated_columns{cn_source} ) { diff --git a/Koha/Items.pm b/Koha/Items.pm index 99429456be..7ac9f034ae 100644 --- a/Koha/Items.pm +++ b/Koha/Items.pm @@ -459,6 +459,7 @@ sub batch_update { my ( @modified_itemnumbers, $modified_fields ); my $i; + my @errors; my $schema = Koha::Database->new->schema; while ( my $item = $self->next ) { @@ -578,6 +579,9 @@ sub batch_update { } ) } catch { + push @errors, { + error => eval { $_->{error} } || "$_", + }; warn $_ }; @@ -600,7 +604,10 @@ sub batch_update { } } - return ( { modified_itemnumbers => \@modified_itemnumbers, modified_fields => $modified_fields }, $self ); + return ( + { modified_itemnumbers => \@modified_itemnumbers, modified_fields => $modified_fields, errors => \@errors }, + $self + ); } =head2 apply_regex diff --git a/Koha/Manual.pm b/Koha/Manual.pm index fe5cc2c5b3..e811c64867 100644 --- a/Koha/Manual.pm +++ b/Koha/Manual.pm @@ -117,6 +117,7 @@ our $mapping = { 'admin/preferences#logs' => '/logspreferences.html', 'admin/preferences#opac' => '/opacpreferences.html', 'admin/preferences#patrons' => '/patronspreferences.html', + 'admin/preferences#reports' => '/reportspreferences.html', 'admin/preferences#searching' => '/searchingpreferences.html', 'admin/preferences#serials' => '/serialspreferences.html', 'admin/preferences#staff_interface' => '/staffclientpreferences.html', diff --git a/Koha/Patron.pm b/Koha/Patron.pm index dcfff7aeb0..cfa570e0f0 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -388,7 +388,7 @@ sub store { if ( C4::Context->preference('ChildNeedsGuarantor') and ( $self->is_child or $self->category->can_be_guarantee ) - and $self->contactname eq "" + and ( !defined $self->contactname || $self->contactname eq "" ) and !@$guarantors ) { Koha::Exceptions::Patron::Relationship::NoGuarantor->throw(); @@ -473,9 +473,8 @@ ListOwnershipUponPatronDeletion pref, but entries from the borrower to other lis sub delete { my ($self) = @_; - my $anonymous_patron = C4::Context->preference("AnonymousPatron"); Koha::Exceptions::Patron::FailedDeleteAnonymousPatron->throw() - if $anonymous_patron && $self->id eq $anonymous_patron; + if $self->is_anonymous; # Check if patron is protected Koha::Exceptions::Patron::FailedDeleteProtectedPatron->throw() if defined $self->protected && $self->protected == 1; @@ -736,8 +735,7 @@ sub siblings { sub merge_with { my ( $self, $patron_ids ) = @_; - my $anonymous_patron = C4::Context->preference("AnonymousPatron"); - return if $anonymous_patron && $self->id eq $anonymous_patron; + return if $self->is_anonymous; # Do not merge other patrons into a protected patron return if $self->protected; @@ -755,12 +753,12 @@ sub merge_with { sub { foreach my $patron_id (@patron_ids) { - next if $anonymous_patron && $patron_id eq $anonymous_patron; - my $patron = Koha::Patrons->find($patron_id); next unless $patron; + next if $patron->is_anonymous; + # Do not merge protected patrons into other patrons next if $patron->protected; @@ -1318,6 +1316,158 @@ sub move_to_deleted { return Koha::Database->new->schema->resultset('Deletedborrower')->create($patron_infos); } +=head3 can_place_holds + + my $result = $patron->can_place_holds(); + my $result = $patron->can_place_holds( + { + overrides => { debt_limit => 1, card_lost => 1 }, + no_short_circuit => 1 + } + ); + + if ( $patron->can_place_holds() ) { + # patron can place holds + } else { + my @messages = $result->messages; + # handle error messages + } + +Checks if a patron is allowed to place holds based on various patron conditions. + +=head4 Parameters + +=over 4 + +=item * C<$options> (optional) - Hashref with the following keys: + +=over 8 + +=item * C - Hashref of checks to skip. Keys should match error message codes. + +=item * C - Boolean. If true, performs all checks and collects all error messages instead of stopping at first failure. Default: false. + +=back + +=back + +=head4 Returns + +Koha::Result::Boolean object - true if patron can place holds, false otherwise. +When false, the result object contains error messages with details about why +holds are blocked. + +=head4 Error Messages + +The following error message codes may be returned: + +=over 4 + +=item * C - Patron account has expired and expired patrons are blocked from placing holds + +=item * C - Patron owes more than the maximum allowed outstanding amount + +=item * C - Patron's address is marked as incorrect + +=item * C - Patron's library card is marked as lost + +=item * C - Patron account is restricted/debarred + +=item * C - Patron has reached the maximum number of allowed holds + +=back + +Error messages may include additional payload data with relevant details +(amounts, limits, counts, etc.). + +=cut + +sub can_place_holds { + my ( $self, $options ) = @_; + $options //= {}; + + my $overrides = $options->{overrides} // {}; + my $no_short_circuit = $options->{no_short_circuit} // 0; + + my $result = Koha::Result::Boolean->new(1); + + # expired patron check + unless ( $overrides->{expired} ) { + if ( $self->is_expired && $self->category->effective_BlockExpiredPatronOpacActions_contains('hold') ) { + $result->set_value(0); + $result->add_message( { message => 'expired', type => 'error' } ); + + return $result unless $no_short_circuit; + } + } + + # debt check + unless ( $overrides->{debt_limit} ) { + my $max_outstanding = C4::Context->preference("maxoutstanding"); + my $outstanding = $self->account->balance; + + if ( $max_outstanding && $outstanding && ( $outstanding > $max_outstanding ) ) { + $result->set_value(0); + $result->add_message( + { + message => 'debt_limit', type => 'error', + payload => { total_outstanding => $outstanding, max_outstanding => $max_outstanding } + } + ); + + return $result unless $no_short_circuit; + } + } + + # check address marked as incorrect + unless ( $overrides->{bad_address} ) { + if ( $self->gonenoaddress ) { + $result->set_value(0); + $result->add_message( { message => 'bad_address', type => 'error' } ); + + return $result unless $no_short_circuit; + } + } + + # check lost card + unless ( $overrides->{card_lost} ) { + if ( $self->lost ) { + $result->set_value(0); + $result->add_message( { message => 'card_lost', type => 'error' } ); + return $result unless $no_short_circuit; + } + } + + # check restrictions + unless ( $overrides->{restricted} ) { + if ( $self->is_debarred ) { + $result->set_value(0); + $result->add_message( { message => 'restricted', type => 'error' } ); + + return $result unless $no_short_circuit; + } + } + + # check max reserves + unless ( $overrides->{hold_limit} ) { + my $max_holds = C4::Context->preference("maxreserves"); + my $holds_count = $self->holds->count; + if ( $max_holds && ( $holds_count >= $max_holds ) ) { + $result->set_value(0); + $result->add_message( + { + message => 'hold_limit', type => 'error', + payload => { total_holds => $holds_count, max_holds => $max_holds } + } + ); + + return $result unless $no_short_circuit; + } + } + + return $result; +} + =head3 can_request_article if ( $patron->can_request_article( $library->id ) ) { ... } @@ -2525,6 +2675,8 @@ sub _anonymize_column { $val = $nullable ? undef : 0; } elsif ( $type =~ /date|time/ ) { $val = $nullable ? undef : dt_from_string; + } elsif ( $type eq 'enum' ) { + $val = $nullable ? undef : $col_info->{default_value}; } $self->$col($val); } @@ -2894,11 +3046,9 @@ This method tells if the Koha:Patron object can be deleted. Possible return valu sub safe_to_delete { my ($self) = @_; - my $anonymous_patron = C4::Context->preference('AnonymousPatron'); - my $error; - if ( $anonymous_patron && $self->id eq $anonymous_patron ) { + if ( $self->is_anonymous ) { $error = 'is_anonymous_patron'; } elsif ( $self->checkouts->count ) { $error = 'has_checkouts'; @@ -3251,6 +3401,20 @@ sub is_patron_inside_charge_limits { return $patron_charge_limits; } +=head3 is_anonymous + +my $is_anonymous_patron= $patron->is_anonymous(); + +Returns true if the patron is the anonymous patron (AnonymousPatron) + +=cut + +sub is_anonymous { + my ($self) = @_; + my $anonymous_patron = C4::Context->preference('AnonymousPatron'); + return ( $anonymous_patron && $self->borrowernumber eq $anonymous_patron ) ? 1 : 0; +} + =head2 Internal methods =head3 _type diff --git a/Koha/Patron/Discharge.pm b/Koha/Patron/Discharge.pm index 7da95ab7c3..1d4b41e84b 100644 --- a/Koha/Patron/Discharge.pm +++ b/Koha/Patron/Discharge.pm @@ -14,6 +14,24 @@ use Koha::DateUtils qw( dt_from_string output_pref ); use Koha::Patrons; use Koha::Patron::Debarments qw( AddDebarment ); +=head1 NAME + +Koha::Patron::Discharge - Koha Discharge object class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 count + + Koha::Patron:Discharge->count; + +Return the number of discharges corresponding to the asked criteria + +=cut + sub count { my ($params) = @_; my $values = {}; @@ -31,6 +49,14 @@ sub count { return search_limited($values)->count; } +=head3 can_be_discharged + + my $can_be_discharged = Koha::Patron:Discharge->can_be_discharged({borrowernumber => $borrowernumber}); + +Return true if the borrower can be discharged + +=cut + sub can_be_discharged { my ($params) = @_; return unless $params->{borrowernumber}; @@ -56,6 +82,14 @@ sub can_be_discharged { return ( $can_be_discharged, $problems ); } +=head3 is_discharged + + my $is_discharged = Koha::Patron:Discharge->is_discharged({borrowernumber => $borrowernumber}); + +Return true if the borrower is discharged + +=cut + sub is_discharged { my ($params) = @_; return unless $params->{borrowernumber}; @@ -71,6 +105,14 @@ sub is_discharged { } } +=head3 request + + my $request = Koha::Patron:Discharge->request({borrowernumber => $borrowernumber}); + +Place a discharge request on a given borrower after checking the borrower has the right to be discharged. + +=cut + sub request { my ($params) = @_; my $borrowernumber = $params->{borrowernumber}; @@ -87,6 +129,14 @@ sub request { ); } +=head3 discharge + + my $request = Koha::Patron:Discharge->discharge({borrowernumber => $borrowernumber}); + +Place a discharge request on a given borrower, if a discharge was requested, update the status to discharged and place a suspension on the user. + +=cut + sub discharge { my ($params) = @_; my $borrowernumber = $params->{borrowernumber}; @@ -124,6 +174,14 @@ sub discharge { } } +=head3 generate_as_pdf + + my $request = Koha::Patron:Discharge->generate_as_pdf({borrowernumber => $borrowernumber}); + +Create a pdf from an existing discharge associated to the borrowernumber. + +=cut + sub generate_as_pdf { my ($params) = @_; return unless $params->{borrowernumber}; @@ -175,6 +233,17 @@ sub generate_as_pdf { return $pdf_path; } +=head3 get_pendings + + my $rs = Koha::Patron:Discharge->get_pendings({ + borrowernumber => $borrowernumber + branchcode => $branchcode + }); + +Get all pending discharges associated to a borrowernumber and/or a given branch + +=cut + sub get_pendings { my ($params) = @_; my $branchcode = $params->{branchcode}; @@ -190,6 +259,17 @@ sub get_pendings { return search_limited($cond); } +=head3 get_validated + + my $rs = Koha::Patron:Discharge->get_validated({ + borrowernumber => $borrowernumber + branchcode => $branchcode + }); + +Get all validated discharges associated to a borrowernumber and/or a given branch + +=cut + sub get_validated { my ($params) = @_; my $branchcode = $params->{branchcode}; @@ -205,6 +285,18 @@ sub get_validated { } # TODO This module should be based on Koha::Object[s] + +=head3 search_limited + + my $rs = Koha::Patron:Discharge->search_limited({ + borrower.branchcode => $branchcode + }, + $attributes); + +Search all discharges that can be seen by the user and fitting the given conditions + +=cut + sub search_limited { my ( $params, $attributes ) = @_; my $userenv = C4::Context->userenv; diff --git a/Koha/Patrons/Import.pm b/Koha/Patrons/Import.pm index 23b6f57803..f36495d76a 100644 --- a/Koha/Patrons/Import.pm +++ b/Koha/Patrons/Import.pm @@ -267,7 +267,10 @@ LINE: while ( my $borrowerline = <$handle> ) { # Remove warning for int datatype that cannot be null # Argument "" isn't numeric in numeric eq (==) at /usr/share/perl5/DBIx/Class/Row.pm line 1018 - for my $field (qw( privacy privacy_guarantor_fines privacy_guarantor_checkouts anonymized login_attempts )) { + for my $field ( + qw( privacy privacy_guarantor_fines privacy_guarantor_checkouts anonymized login_attempts checkprevcheckout autorenew_checkouts ) + ) + { delete $borrower{$field} if exists $borrower{$field} and $borrower{$field} eq ""; } @@ -304,7 +307,8 @@ LINE: while ( my $borrowerline = <$handle> ) { next if $col eq 'password' && !$overwrite_passwords; next if $col eq 'dateexpiry' && $update_dateexpiry; - $borrower{$col} = $member->{$col} if $col eq 'dateexpiry' && !$columns[ $csvkeycol{$col} ]; + $borrower{$col} = $member->{$col} + if $col eq 'dateexpiry' && ( !$csvkeycol{$col} || !$columns[ $csvkeycol{$col} ] ); unless ( exists( $csvkeycol{$col} ) || $defaults->{$col} ) { $borrower{$col} = $member->{$col} if ( $member->{$col} ); diff --git a/Koha/Quotes.pm b/Koha/Quotes.pm index 95eccd50d4..9dadb5de8d 100644 --- a/Koha/Quotes.pm +++ b/Koha/Quotes.pm @@ -71,7 +71,7 @@ sub get_daily_quote { my $dt = $dtf->format_date(dt_from_string); $quote = $self->search( { - timestamp => { -between => => [ "$dt 00:00:00", "$dt 23:59:59" ] }, + timestamp => { -between => [ "$dt 00:00:00", "$dt 23:59:59" ] }, }, { order_by => { -desc => 'timestamp' }, diff --git a/Koha/REST/V1/CirculationRules.pm b/Koha/REST/V1/CirculationRules.pm index 74c54b813d..81bd51fc81 100644 --- a/Koha/REST/V1/CirculationRules.pm +++ b/Koha/REST/V1/CirculationRules.pm @@ -2,18 +2,18 @@ package Koha::REST::V1::CirculationRules; # 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 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. +# 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/REST/V1/Holds.pm b/Koha/REST/V1/Holds.pm index 7f8764e6cb..33c885774c 100644 --- a/Koha/REST/V1/Holds.pm +++ b/Koha/REST/V1/Holds.pm @@ -88,7 +88,9 @@ sub add { my $non_priority = $body->{non_priority}; my $overrides = $c->stash('koha.overrides'); - my $can_override = $overrides->{any} && C4::Context->preference('AllowHoldPolicyOverride'); + my $can_override = C4::Context->preference('AllowHoldPolicyOverride') // 0; + + my $override_all = $overrides->{any} && C4::Context->preference('AllowHoldPolicyOverride') ? 1 : 0; if ( !C4::Context->preference('AllowHoldDateInFuture') && $hold_date ) { return $c->render( @@ -142,7 +144,7 @@ sub add { } # If the hold is being forced, no need to validate - unless ($can_override) { + unless ($override_all) { # Validate pickup location my $valid_pickup_location; @@ -161,21 +163,28 @@ sub add { openapi => { error => 'The supplied pickup location is not valid' } ) unless $valid_pickup_location; - my $can_place_hold = + my $can_place_holds = $patron->can_place_holds( { overrides => $overrides } ); + + if ( !$can_place_holds ) { + my $error_code = $can_place_holds->messages->[0]->message; + return $c->render( + status => 409, + openapi => { + error => 'Hold cannot be placed. Reason: ' . $error_code, + error_code => $error_code, + } + ); + } + + my $can_hold_be_placed = $item ? C4::Reserves::CanItemBeReserved( $patron, $item ) : C4::Reserves::CanBookBeReserved( $patron_id, $biblio_id ); - if ( C4::Context->preference('maxreserves') - && $patron->holds->count + 1 > C4::Context->preference('maxreserves') ) - { - $can_place_hold->{status} = 'tooManyReserves'; - } - - unless ( $can_place_hold->{status} eq 'OK' ) { + unless ( $can_hold_be_placed->{status} eq 'OK' ) { return $c->render( status => 403, - openapi => { error => "Hold cannot be placed. Reason: " . $can_place_hold->{status} } + openapi => { error => "Hold cannot be placed. Reason: " . $can_hold_be_placed->{status} } ); } } diff --git a/Koha/REST/V1/Suggestions.pm b/Koha/REST/V1/Suggestions.pm index 9c3a0a0d50..442a36a8ec 100644 --- a/Koha/REST/V1/Suggestions.pm +++ b/Koha/REST/V1/Suggestions.pm @@ -2,17 +2,18 @@ package Koha::REST::V1::Suggestions; # 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 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. +# 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 . +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/Report.pm b/Koha/Report.pm index 54511cdc4c..8c292a16a8 100644 --- a/Koha/Report.pm +++ b/Koha/Report.pm @@ -20,9 +20,13 @@ use Modern::Perl; use Koha::Database; use Koha::Reports; +use Koha::Object; +use Koha::Object::Limit::Library; + +use base qw(Koha::Object Koha::Object::Limit::Library); + #use Koha::DateUtils qw( dt_from_string output_pref ); -use base qw(Koha::Object); # # FIXME We could only return an error code instead of the arrayref # Only 1 error is returned @@ -268,4 +272,18 @@ sub _type { return 'SavedSql'; } +=head3 _library_limits + +Configurable library limits + +=cut + +sub _library_limits { + return { + class => "ReportsBranch", + id => "report_id", + library => "branchcode", + }; +} + 1; diff --git a/Koha/Reports.pm b/Koha/Reports.pm index 7d99232b9b..387c72abb1 100644 --- a/Koha/Reports.pm +++ b/Koha/Reports.pm @@ -21,7 +21,7 @@ use Koha::Database; use Koha::Report; -use base qw(Koha::Objects); +use base qw(Koha::Objects Koha::Objects::Limit::Library); =head1 NAME @@ -33,6 +33,33 @@ Koha::Reports - Koha Report Object set class =cut +=head3 search_with_localization + +my $itemtypes = Koha::ItemTypes->search_with_localization + +=cut + +sub search_with_localization { + my ( $self, $params, $attributes ) = @_; + + my $language = C4::Languages::getlanguage(); + $Koha::Schema::Result::Itemtype::LANGUAGE = $language; + $attributes->{order_by} = 'translated_description' unless exists $attributes->{order_by}; + $attributes->{join} = 'localization'; + $attributes->{'+select'} = [ + { + coalesce => [qw( localization.translation me.description )], + -as => 'translated_description' + } + ]; + if ( defined $params->{branchcode} ) { + my $branchcode = delete $params->{branchcode}; + $self->search_with_library_limits( $params, $attributes, $branchcode ); + } else { + $self->SUPER::search( $params, $attributes ); + } +} + =head3 _type Returns name of corresponding DBIC resultset diff --git a/Koha/Schema/Result/Borrower.pm b/Koha/Schema/Result/Borrower.pm index 2e1a5e9d51..1e1fa11cd4 100644 --- a/Koha/Schema/Result/Borrower.pm +++ b/Koha/Schema/Result/Borrower.pm @@ -582,10 +582,10 @@ controls if relatives can see this patron's checkouts =head2 checkprevcheckout - data_type: 'varchar' + data_type: 'enum' default_value: 'inherit' + extra: {list => ["yes","no","inherit"]} is_nullable: 0 - size: 7 produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'. @@ -832,10 +832,10 @@ __PACKAGE__->add_columns( { data_type => "tinyint", default_value => 0, is_nullable => 0 }, "checkprevcheckout", { - data_type => "varchar", + data_type => "enum", default_value => "inherit", + extra => { list => ["yes", "no", "inherit"] }, is_nullable => 0, - size => 7, }, "updated_on", { @@ -2197,8 +2197,8 @@ Composing rels: L -> permission __PACKAGE__->many_to_many("permissions", "user_permissions", "permission"); -# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-04-28 16:41:47 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:J1oaW0hFRihEJZ6U+XSwag +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-07-10 07:11:31 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:XFOe2X4k2DUziaNS5pWd/Q __PACKAGE__->belongs_to( "library", diff --git a/Koha/Schema/Result/Category.pm b/Koha/Schema/Result/Category.pm index 62c6e3fb4d..9cb9622295 100644 --- a/Koha/Schema/Result/Category.pm +++ b/Koha/Schema/Result/Category.pm @@ -136,10 +136,10 @@ Default privacy setting for this patron category =head2 checkprevcheckout - data_type: 'varchar' + data_type: 'enum' default_value: 'inherit' + extra: {list => ["yes","no","inherit"]} is_nullable: 0 - size: 7 produce a warning for this patron category if this item has previously been checked out to this patron if 'yes', not if 'no', defer to syspref setting if 'inherit'. @@ -274,10 +274,10 @@ __PACKAGE__->add_columns( }, "checkprevcheckout", { - data_type => "varchar", + data_type => "enum", default_value => "inherit", + extra => { list => ["yes", "no", "inherit"] }, is_nullable => 0, - size => 7, }, "can_place_ill_in_opac", { data_type => "tinyint", default_value => 1, is_nullable => 0 }, @@ -410,8 +410,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-03 15:46:23 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jiQq3bW+ZfdYpUpfZq1Rzw +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-07-10 07:11:31 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ADt+iDjteg9Jb81L2FMIvg # You can replace this text with custom code or comments, and it will be preserved on regeneration diff --git a/Koha/Schema/Result/Deletedborrower.pm b/Koha/Schema/Result/Deletedborrower.pm index b2decd87d2..5d0f10facb 100644 --- a/Koha/Schema/Result/Deletedborrower.pm +++ b/Koha/Schema/Result/Deletedborrower.pm @@ -579,10 +579,10 @@ controls if relatives can see this patron's checkouts =head2 checkprevcheckout - data_type: 'varchar' + data_type: 'enum' default_value: 'inherit' + extra: {list => ["yes","no","inherit"]} is_nullable: 0 - size: 7 produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit'. @@ -817,10 +817,10 @@ __PACKAGE__->add_columns( { data_type => "tinyint", default_value => 0, is_nullable => 0 }, "checkprevcheckout", { - data_type => "varchar", + data_type => "enum", default_value => "inherit", + extra => { list => ["yes", "no", "inherit"] }, is_nullable => 0, - size => 7, }, "updated_on", { @@ -857,8 +857,8 @@ __PACKAGE__->add_columns( ); -# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-04-28 16:41:47 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:5QA+/eORyEKhkG++0f3Hvw +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-07-10 07:11:31 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vAkNNQagJcYfZ0/6mDOw8g __PACKAGE__->add_columns( '+anonymized' => { is_boolean => 1 }, diff --git a/Koha/Schema/Result/ReportsBranch.pm b/Koha/Schema/Result/ReportsBranch.pm new file mode 100644 index 0000000000..970c25eabc --- /dev/null +++ b/Koha/Schema/Result/ReportsBranch.pm @@ -0,0 +1,85 @@ +use utf8; + +package Koha::Schema::Result::ReportsBranch; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::ReportsBranch + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("reports_branches"); + +=head1 ACCESSORS + +=head2 report_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +=head2 branchcode + + data_type: 'varchar' + is_foreign_key: 1 + is_nullable: 0 + size: 10 + +=cut + +__PACKAGE__->add_columns( + "report_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "branchcode", + { data_type => "varchar", is_foreign_key => 1, is_nullable => 0, size => 10 }, +); + +=head1 RELATIONS + +=head2 branchcode + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "branchcode", + "Koha::Schema::Result::Branch", + { branchcode => "branchcode" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "RESTRICT" }, +); + +=head2 report + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "report", + "Koha::Schema::Result::SavedSql", + { id => "report_id" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "RESTRICT" }, +); + +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-07-06 17:02:11 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SJqUxMgLJHAjbX3GJlpB+A + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/Koha/Schema/Result/SavedSql.pm b/Koha/Schema/Result/SavedSql.pm index 6f75ae3b31..4f063e8d67 100644 --- a/Koha/Schema/Result/SavedSql.pm +++ b/Koha/Schema/Result/SavedSql.pm @@ -185,6 +185,221 @@ __PACKAGE__->add_columns( __PACKAGE__->set_primary_key("id"); +=head1 RELATIONS + +=head2 reports_branches + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "reports_branches", + "Koha::Schema::Result::ReportsBranch", + { "foreign.report_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07051 @ 2025-07-06 17:02:11 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:qFqDaOxgdm2I12cJEiCieg +# These lines were loaded from '/kohadevbox/koha/Koha/Schema/Result/SavedSql.pm' found in @INC. +# They are now part of the custom portion of this file +# for you to hand-edit. If you do not either delete +# this section or remove that file from @INC, this section +# will be repeated redundantly when you re-create this +# file again via Loader! See skip_load_external to disable +# this feature. + +use utf8; +package Koha::Schema::Result::SavedSql; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::SavedSql + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("saved_sql"); + +=head1 ACCESSORS + +=head2 id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +unique id and primary key assigned by Koha + +=head2 borrowernumber + + data_type: 'integer' + is_nullable: 1 + +the staff member who created this report (borrowers.borrowernumber) + +=head2 date_created + + data_type: 'datetime' + datetime_undef_if_invalid: 1 + is_nullable: 1 + +the date this report was created + +=head2 last_modified + + data_type: 'datetime' + datetime_undef_if_invalid: 1 + is_nullable: 1 + +the date this report was last edited + +=head2 savedsql + + data_type: 'mediumtext' + is_nullable: 1 + +the SQL for this report + +=head2 last_run + + data_type: 'datetime' + datetime_undef_if_invalid: 1 + is_nullable: 1 + +=head2 report_name + + data_type: 'varchar' + default_value: (empty string) + is_nullable: 0 + size: 255 + +the name of this report + +=head2 type + + data_type: 'varchar' + is_nullable: 1 + size: 255 + +always 1 for tabular + +=head2 notes + + data_type: 'mediumtext' + is_nullable: 1 + +the notes or description given to this report + +=head2 cache_expiry + + data_type: 'integer' + default_value: 300 + is_nullable: 0 + +=head2 public + + data_type: 'tinyint' + default_value: 0 + is_nullable: 0 + +=head2 report_area + + data_type: 'varchar' + is_nullable: 1 + size: 6 + +=head2 report_group + + data_type: 'varchar' + is_nullable: 1 + size: 80 + +=head2 report_subgroup + + data_type: 'varchar' + is_nullable: 1 + size: 80 + +=head2 mana_id + + data_type: 'integer' + is_nullable: 1 + +=cut + +__PACKAGE__->add_columns( + "id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "borrowernumber", + { data_type => "integer", is_nullable => 1 }, + "date_created", + { + data_type => "datetime", + datetime_undef_if_invalid => 1, + is_nullable => 1, + }, + "last_modified", + { + data_type => "datetime", + datetime_undef_if_invalid => 1, + is_nullable => 1, + }, + "savedsql", + { data_type => "mediumtext", is_nullable => 1 }, + "last_run", + { + data_type => "datetime", + datetime_undef_if_invalid => 1, + is_nullable => 1, + }, + "report_name", + { data_type => "varchar", default_value => "", is_nullable => 0, size => 255 }, + "type", + { data_type => "varchar", is_nullable => 1, size => 255 }, + "notes", + { data_type => "mediumtext", is_nullable => 1 }, + "cache_expiry", + { data_type => "integer", default_value => 300, is_nullable => 0 }, + "public", + { data_type => "tinyint", default_value => 0, is_nullable => 0 }, + "report_area", + { data_type => "varchar", is_nullable => 1, size => 6 }, + "report_group", + { data_type => "varchar", is_nullable => 1, size => 80 }, + "report_subgroup", + { data_type => "varchar", is_nullable => 1, size => 80 }, + "mana_id", + { data_type => "integer", is_nullable => 1 }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("id"); + # Created by DBIx::Class::Schema::Loader v0.07049 @ 2021-01-21 13:39:29 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:198dNG9DGQzop+s5IHy7sw @@ -214,3 +429,8 @@ sub koha_objects_class { } 1; +# End of lines loaded from '/kohadevbox/koha/Koha/Schema/Result/SavedSql.pm' + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; \ No newline at end of file diff --git a/Koha/SearchEngine/Elasticsearch/Search.pm b/Koha/SearchEngine/Elasticsearch/Search.pm index c88345bb58..e81d1df84e 100644 --- a/Koha/SearchEngine/Elasticsearch/Search.pm +++ b/Koha/SearchEngine/Elasticsearch/Search.pm @@ -54,6 +54,9 @@ use MARC::File::XML; use MIME::Base64 qw( decode_base64 ); use JSON; +use POSIX qw(setlocale LC_COLLATE); +use Unicode::Collate::Locale; + Koha::SearchEngine::Elasticsearch::Search->mk_accessors(qw( store )); =head2 search @@ -453,6 +456,42 @@ sub max_result_window { return $max_result_window; } +=head2 _sort_facets + + my $facets = _sort_facets($facets); + +Sorts facets using a locale. + +=cut + +sub _sort_facets { + my ( $self, $args ) = @_; + my $facets = $args->{facets}; + my $locale = $args->{locale}; + + if ( !$locale ) { + + # Get locale from system preference, falling back to system LC_COLLATE + $locale = C4::Context->preference('FacetSortingLocale') || 'default'; + if ( $locale eq 'default' || !$locale ) { + + #NOTE: When setlocale is run with only the 1st parameter, it is a "get" not a "set" function. + $locale = setlocale(LC_COLLATE) || 'default'; + } + } + + my $collator = Unicode::Collate::Locale->new( locale => $locale ); + if ( $collator && $facets ) { + my @sorted_facets = sort { $collator->cmp( $a->{facet_label_value}, $b->{facet_label_value} ) } @{$facets}; + if (@sorted_facets) { + return \@sorted_facets; + } + } + + #NOTE: If there was a problem, at least return the not sorted facets + return $facets; +} + =head2 _convert_facets my $koha_facets = _convert_facets($es_facets); @@ -526,14 +565,16 @@ sub _convert_facets { facet_count => $c, facet_link_value => $t, facet_title_value => $t, - facet_label_value => $label, # TODO either truncate this, - # or make the template do it like it should anyway + facet_label_value => $label || q{}, # TODO either truncate this, + # or make the template do it like it should anyway type_link_value => $type, }; } if ( C4::Context->preference('FacetOrder') eq 'Alphabetical' ) { - @{ $facet->{facets} } = - sort { $a->{facet_label_value} cmp $b->{facet_label_value} } @{ $facet->{facets} }; + my $sorted_facets = $self->_sort_facets( { facets => $facet->{facets} } ); + if ($sorted_facets) { + $facet->{facets} = $sorted_facets; + } } push @facets, $facet if exists $facet->{facets}; } diff --git a/acqui/basket.pl b/acqui/basket.pl index 791acd3250..57621b4e7a 100755 --- a/acqui/basket.pl +++ b/acqui/basket.pl @@ -613,16 +613,20 @@ sub edi_close_and_order { } exit; } else { + + my $ean_description = $query->param('ean_description'); + my $ean_branch = $query->param('ean_branch'); + $template->param( edi_confirm => 1, booksellerid => $booksellerid, basketno => $basket->{basketno}, basketname => $basket->{basketname}, basketgroupname => $basket->{basketname}, + ean => $ean ? $ean : '', + ean_description => $ean_description ? $ean_description : '', + ean_branch => $ean_branch ? $ean_branch : '', ); - if ($ean) { - $template->param( ean => $ean ); - } } return; diff --git a/acqui/newordersuggestion.pl b/acqui/newordersuggestion.pl index e41381f4f4..344cf79148 100755 --- a/acqui/newordersuggestion.pl +++ b/acqui/newordersuggestion.pl @@ -93,7 +93,7 @@ use Modern::Perl; use CGI qw ( -utf8 ); use C4::Auth qw( get_template_and_user ); use C4::Output qw( output_html_with_http_headers ); -use C4::Suggestions qw( ConnectSuggestionAndBiblio ); +use C4::Suggestions qw( ConnectSuggestionAndBiblio ModSuggestion ); use C4::Budgets; use Koha::Acquisition::Booksellers; @@ -111,6 +111,7 @@ my $op = $input->param('op'); my $suggestionid = $input->param('suggestionid'); my $duplicateNumber = $input->param('duplicateNumber'); my $uncertainprice = $input->param('uncertainprice'); +my $link_order = $input->param('link_order'); $op = 'else' unless $op; @@ -128,6 +129,28 @@ if ( $op eq 'connectDuplicate' ) { ConnectSuggestionAndBiblio( $suggestionid, $duplicateNumber ); } +if ( $op eq 'cud-link_order' and $link_order ) { + my $order = Koha::Acquisition::Orders->find($link_order); + + if ( $order->biblionumber ) { + ModSuggestion( + { + suggestionid => $suggestionid, + biblionumber => $order->biblionumber, + STATUS => 'ORDERED', + } + ); + if ( C4::Context->preference('PlaceHoldsOnOrdersFromSuggestions') ) { + my $suggestion = Koha::Suggestions->find($suggestionid); + if ($suggestion) { + $suggestion->place_hold(); + } + } + } + + print $input->redirect( "/cgi-bin/koha/acqui/basket.pl?basketno=" . $basketno ); +} + my $suggestions = [ Koha::Suggestions->search_limited( { @@ -147,6 +170,7 @@ $template->param( booksellerid => $booksellerid, name => $vendor->name, "op_$op" => 1, + link_order => $link_order, ); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/admin/columns_settings.yml b/admin/columns_settings.yml index f482000815..21e8e8a618 100644 --- a/admin/columns_settings.yml +++ b/admin/columns_settings.yml @@ -736,6 +736,8 @@ modules: columnname: withdrawn_status - columnname: damaged_status + - + columnname: dateaccessioned - columnname: checkouts - @@ -1445,6 +1447,8 @@ modules: columnname: itemtype - columnname: status + - + columnname: notes checkouthistory: checkouthistory-table: @@ -1453,6 +1457,7 @@ modules: - columnname: type cannot_be_toggled: 1 cannot_be_modified: 1 + is_hidden: 1 - columnname: date - @@ -2580,4 +2585,4 @@ modules: - columnname: actions cannot_be_toggled: 1 - cannot_be_modified: 1 \ No newline at end of file + cannot_be_modified: 1 diff --git a/admin/preferences.pl b/admin/preferences.pl index 34ddca9497..bf67c87e74 100755 --- a/admin/preferences.pl +++ b/admin/preferences.pl @@ -122,6 +122,18 @@ sub _get_chunk { } $chunk->{'languages'} = getTranslatedLanguages( $interface, $theme ); $chunk->{'type'} = 'languages'; + } elsif ( $options{'type'} && $options{'type'} eq 'locale-list' ) { + + # Dynamic locale detection for facet sorting using Koha::I18N + require Koha::I18N; + my $locales = Koha::I18N::available_locales(); + foreach my $locale (@$locales) { + if ( $locale->{value} && $value && $locale->{value} eq $value ) { + $locale->{selected} = 1; + } + } + $chunk->{'CHOICES'} = $locales; + $chunk->{'type'} = 'select'; } elsif ( $options{'choices'} ) { my $add_blank; if ( $options{'choices'} && ref( $options{'choices'} ) eq '' ) { diff --git a/api/v1/swagger/definitions/item.yaml b/api/v1/swagger/definitions/item.yaml index fd1bbd11c9..42dcd36e3e 100644 --- a/api/v1/swagger/definitions/item.yaml +++ b/api/v1/swagger/definitions/item.yaml @@ -12,6 +12,7 @@ properties: - string - "null" description: The item's barcode + maxLength: 20 acquisition_date: type: - string @@ -36,6 +37,7 @@ properties: - string - "null" description: Internal library id for the library the item belongs to + maxLength: 10 purchase_price: type: - number @@ -103,11 +105,13 @@ properties: - string - "null" description: Call number for this item + maxLength: 255 coded_location_qualifier: type: - string - "null" description: Coded location qualifier + maxLength: 10 checkouts_count: type: - integer @@ -148,6 +152,7 @@ properties: - string - "null" description: Library that is currently in possession item + maxLength: 10 timestamp: type: string format: date-time @@ -157,6 +162,7 @@ properties: - string - "null" description: Authorized value for the shelving location for this item + maxLength: 80 permanent_location: type: - string @@ -164,6 +170,7 @@ properties: description: Linked to the CART and PROC temporary locations feature, stores the permanent shelving location + maxLength: 80 checked_out_date: type: - string @@ -177,16 +184,19 @@ properties: - string - "null" description: Classification source used on this item + maxLength: 10 call_number_sort: type: - string - "null" description: "?" + maxLength: 255 collection_code: type: - string - "null" description: Authorized value for the collection code associated with this item + maxLength: 80 materials_notes: type: - string @@ -207,6 +217,7 @@ properties: - string - "null" description: Itemtype defining the type for this item + maxLength: 10 effective_item_type_id: type: - string @@ -227,16 +238,19 @@ properties: - string - "null" description: Copy number + maxLength: 32 inventory_number: type: - string - "null" description: Inventory number + maxLength: 80 new_status: type: - string - "null" description: "'new' value, whatever free-text information." + maxLength: 32 exclude_from_local_holds_priority: type: boolean description: Exclude this item from local holds priority. diff --git a/api/v1/swagger/definitions/library.yaml b/api/v1/swagger/definitions/library.yaml index 0fc7967358..9039fbb847 100644 --- a/api/v1/swagger/definitions/library.yaml +++ b/api/v1/swagger/definitions/library.yaml @@ -29,6 +29,7 @@ properties: - string - "null" description: the postal code of the library + maxLength: 25 city: type: - string @@ -84,6 +85,7 @@ properties: - string - "null" description: the IP address for your library or branch + maxLength: 15 notes: type: - string @@ -94,6 +96,7 @@ properties: - string - "null" description: geolocation of your library + maxLength: 255 marc_org_code: type: - string @@ -101,6 +104,7 @@ properties: description: MARC Organization Code, see http://www.loc.gov/marc/organizations/orgshome.html, when empty defaults to syspref MARCOrgCode + maxLength: 16 pickup_location: type: boolean description: If the library can act as a pickup location diff --git a/api/v1/swagger/definitions/patron.yaml b/api/v1/swagger/definitions/patron.yaml index 4b61ae2d46..72f64fac15 100644 --- a/api/v1/swagger/definitions/patron.yaml +++ b/api/v1/swagger/definitions/patron.yaml @@ -9,6 +9,7 @@ properties: - string - "null" description: library assigned user identifier + maxLength: 32 surname: type: - string @@ -178,9 +179,11 @@ properties: library_id: type: string description: Internal identifier for the patron's home library + maxLength: 10 category_id: type: string description: Internal identifier for the patron's category + maxLength: 10 date_enrolled: type: - string @@ -227,16 +230,19 @@ properties: - string - "null" description: used for children to include the relationship to their guarantor + maxLength: 100 gender: type: - string - "null" description: patron's gender + maxLength: 1 userid: type: - string - "null" description: patron's login + maxLength: 75 opac_notes: type: - string @@ -247,16 +253,19 @@ properties: - string - "null" description: a note related to patron's alternate address + maxLength: 255 statistics_1: type: - string - "null" description: a field that can be used for any information unique to the library + maxLength: 80 statistics_2: type: - string - "null" description: a field that can be used for any information unique to the library + maxLength: 80 autorenew_checkouts: type: boolean description: indicate whether auto-renewal is allowed for patron @@ -311,6 +320,7 @@ properties: - "null" description: the mobile phone number where the patron would like to receive notices (if SMS turned on) + maxLength: 50 sms_provider_id: type: - integer @@ -327,6 +337,10 @@ properties: description: controls if relatives can see this patron's fines check_previous_checkout: type: string + enum: + - yes + - no + - inherit description: produce a warning for this patron if this item has previously been checked out to this patron if 'yes', not if 'no', defer to category setting if 'inherit' @@ -344,6 +358,7 @@ properties: lang: type: string description: lang to use to send notices to this patron + maxLength: 25 login_attempts: type: - integer diff --git a/api/v1/swagger/definitions/patron_category.yaml b/api/v1/swagger/definitions/patron_category.yaml index 7f2d4a3288..da548a6980 100644 --- a/api/v1/swagger/definitions/patron_category.yaml +++ b/api/v1/swagger/definitions/patron_category.yaml @@ -4,6 +4,7 @@ properties: patron_category_id: type: string description: Internal patron category identifier + maxLength: 10 name: type: - string @@ -56,9 +57,11 @@ properties: category_type: type: string description: Type of Koha patron (Adult, Child, Professional, Organizational, Statistical, Staff) + maxLength: 1 block_expired_patron_opac_actions: type: string description: Specific actions expired patrons of this category are blocked from performing. OPAC actions blocked based on the patron category take priority over this preference + maxLength: 128 default_privacy: type: string enum: @@ -68,6 +71,10 @@ properties: description: Default privacy setting for this patron category check_prev_checkout: type: string + enum: + - yes + - no + - inherit description: Produce a warning for this patron category if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to syspref setting if ''inherit''.' can_place_ill_in_opac: type: boolean diff --git a/api/v1/swagger/paths/holds.yaml b/api/v1/swagger/paths/holds.yaml index cac6627018..4fe775fb36 100644 --- a/api/v1/swagger/paths/holds.yaml +++ b/api/v1/swagger/paths/holds.yaml @@ -221,6 +221,12 @@ type: string enum: - any + - bad_address + - card_lost + - debt_limit + - expired + - hold_limit + - restricted collectionFormat: csv consumes: - application/json @@ -247,6 +253,18 @@ description: Borrower not found schema: $ref: "../swagger.yaml#/definitions/error" + "409": + description: | + Conflict. Possible `error_code` attribute values: + + * `bad_address` + * `card_lost` + * `debt_limit` + * `expired` + * `hold_limit` + * `restricted` + schema: + $ref: "../swagger.yaml#/definitions/error" "500": description: | Internal server error. Possible `error_code` attribute values: diff --git a/catalogue/moredetail.pl b/catalogue/moredetail.pl index 3e848377bc..78688a925d 100755 --- a/catalogue/moredetail.pl +++ b/catalogue/moredetail.pl @@ -81,9 +81,10 @@ my $title = $query->param('title'); my $bi = $query->param('bi'); $bi = $biblionumber unless $bi; $itemnumber = $query->param('itemnumber'); -my $data = &GetBiblioData($biblionumber); -my $dewey = $data->{'dewey'}; -my $showallitems = $query->param('showallitems'); +my $data = &GetBiblioData($biblionumber); +my $dewey = $data->{'dewey'}; +my $showallitems = $query->param('showallitems'); +my $withdraw_error = $query->param('nowithdraw'); #coping with subscriptions my $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber); @@ -325,6 +326,7 @@ $template->param( ); $template->param( + withdraw_error => $withdraw_error, ITEM_DATA => \@item_data, moredetailview => 1, loggedinuser => $loggedinuser, @@ -341,4 +343,3 @@ my $holds = $biblio->holds; $template->param( holdcount => $holds->count ); output_html_with_http_headers $query, $cookie, $template->output; - diff --git a/catalogue/updateitem.pl b/catalogue/updateitem.pl index 350f4b14e4..d02fe66951 100755 --- a/catalogue/updateitem.pl +++ b/catalogue/updateitem.pl @@ -90,9 +90,13 @@ if ( $op eq "cud-set_non_public_note" ) { print $cgi->redirect("moredetail.pl?biblionumber=$biblionumber&itemnumber=$itemnumber#item$itemnumber"); exit; } - -$item->store; - +eval { $item->store; }; +if ($@) { + my $error_message = $@->message; + print $cgi->redirect( + "moredetail.pl?biblionumber=$biblionumber&itemnumber=$itemnumber&nowithdraw=$error_message#item$itemnumber"); + exit; +} LostItem( $itemnumber, 'moredetail' ) if $op eq "cud-set_lost"; print $cgi->redirect( diff --git a/cataloguing/addbiblio.pl b/cataloguing/addbiblio.pl index 58f555d6de..51fbb1a31d 100755 --- a/cataloguing/addbiblio.pl +++ b/cataloguing/addbiblio.pl @@ -33,7 +33,6 @@ use C4::Biblio qw( GetMarcStructure GetUsedMarcStructure ModBiblio - prepare_host_field PrepHostMarcField TransformHtmlToMarc ApplyMarcOverlayRules @@ -645,8 +644,10 @@ if ($hostbiblionumber) { if ($parentbiblio) { my $marcflavour = C4::Context->preference('marcflavour'); $record = MARC::Record->new(); + $record->leader(' naa a22 i 4500'); SetMarcUnicodeFlag( $record, $marcflavour ); - my $hostfield = prepare_host_field( $parentbiblio, $marcflavour ); + my $parent = Koha::Biblios->find($parentbiblio); + my $hostfield = $parent->generate_marc_host_field; if ($hostfield) { $record->append_fields($hostfield); } diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl index fecd4fa6a8..c1067f44bf 100755 --- a/cataloguing/additem.pl +++ b/cataloguing/additem.pl @@ -50,6 +50,7 @@ use MARC::File::XML; use MIME::Base64 qw( decode_base64url encode_base64url ); use Storable qw( freeze thaw ); use URI::Escape qw( uri_escape_utf8 ); +use Try::Tiny qw( catch try ); our $dbh = C4::Context->dbh; @@ -641,7 +642,11 @@ if ( $op eq "cud-additem" ) { if ( $newitemlost && $newitemlost ge '1' && !$olditemlost ) { LostItem( $item->itemnumber, 'additem' ); } - $item->store; + try { + $item->store; + } catch { + push @errors, $_->error; + } } $nextop = "cud-additem"; diff --git a/circ/circulation.pl b/circ/circulation.pl index 5d432b4f80..52871d12b9 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -626,7 +626,7 @@ if ($patron) { $template->param( is_debarred => 1 ); $noissues = 1; } - if ( $patron->borrowernumber eq C4::Context->preference("AnonymousPatron") ) { + if ( $patron->is_anonymous ) { $template->param( is_anonymous => 1 ); $noissues = 1; } diff --git a/cpanfile b/cpanfile index c0fc0ef00b..84d6e4ede0 100644 --- a/cpanfile +++ b/cpanfile @@ -107,6 +107,7 @@ requires 'Storable', '2.20'; requires 'String::Random', '0.22'; requires 'Template', '>= 2.27, != 3.008'; requires 'Template::Plugin::HtmlToText', '0.03'; +requires 'Template::Plugin::JSON', '0.08', requires 'Template::Plugin::JSON::Escape', '0.02'; requires 'Term::ANSIColor', '1.1'; requires 'Test', '1.25'; diff --git a/cypress.config.ts b/cypress.config.ts index e90da4e019..b7bba5408c 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -12,16 +12,13 @@ export default defineConfig({ return require("./t/cypress/plugins/index.js")(on, config); }, experimentalStudio: true, - baseUrl: "http://localhost:8081", + baseUrl: process.env.KOHA_INTRANET_URL || "http://localhost:8081", specPattern: "t/cypress/integration/**/*.*", supportFile: "t/cypress/support/e2e.js", env: { - db: { - host: "db", - user: "koha_kohadev", - password: "password", - database: "koha_kohadev", - }, + opacBaseUrl: process.env.KOHA_OPAC_URL || "http://localhost:8080", + apiUsername: "koha", + apiPassword: "koha", }, }, }); diff --git a/debian/build-git-snapshot b/debian/build-git-snapshot index 7000abc9eb..a426507fef 100755 --- a/debian/build-git-snapshot +++ b/debian/build-git-snapshot @@ -24,38 +24,45 @@ use Modern::Perl; use Getopt::Long qw(:config no_ignore_case); -use POSIX qw/strftime/; +use POSIX qw/strftime/; my $basetgz; my $buildresult; -my $distribution='squeeze-dev'; -my $git_checks='all'; -my $version='16.06~git'; -my $auto_version=1; +my $distribution = 'testing'; +my $git_checks = 'all'; +my $version = '16.06~git'; +my $auto_version = 1; +my $auto_changelog = 1; my $need_help; +my $incr; +my $urgency = 'medium'; my $debug; +my $release_str; + GetOptions( 'basetgz|b=s' => \$basetgz, - 'buildresult|r=s' => \$buildresult, - 'distribution|D=s' => \$distribution, - 'git-checks|g=s' => \$git_checks, - 'version|v=s' => \$version, - 'autoversion!' => \$auto_version, - 'help|h' => \$need_help, - 'debug|d' => \$debug, + 'buildresult|r=s' => \$buildresult, + 'distribution|D=s' => \$distribution, + 'git-checks|g=s' => \$git_checks, + 'version|v=s' => \$version, + 'incr|i=s' => \$incr, + 'urgency|u=s' => \$urgency, + 'autoversion!' => \$auto_version, + 'autochangelog!' => \$auto_changelog, + 'help|h' => \$need_help, + 'debug|d' => \$debug, ); help_and_exit() if $need_help; - sub sys_command_output { my ($command) = @_; print "$command\n" if $debug; my $command_output; - open($command_output, "-|", "$command ") - or die qq{Cannot execute "$command": $!"}; + open( $command_output, "-|", "$command " ) + or die qq{Cannot execute "$command": $!"}; return map { chomp; $_ } <$command_output>; } @@ -70,17 +77,17 @@ sub everything_is_committed { my $filter; for ($git_checks) { $_ eq "none" - and return 1; + and return 1; $_ eq "modified" - and $filter = "no", - last; + and $filter = "no", + last; $_ eq "all" - and $filter = "normal", - last; + and $filter = "normal", + last; - help_and_exit("$0: --git-checks/-g must be one of 'all', 'modified', or 'none'"); + help_and_exit("$0: --git-checks/-g must be one of 'all', 'modified', or 'none'"); } my $has_changes = grep /^xxx/, sys_command_output("git status --porcelain -u${filter}"); @@ -88,13 +95,13 @@ sub everything_is_committed { } sub help_and_exit { - my $msg = shift; - if ($msg) { - print "$msg\n\n"; + my $msg = shift; + if ($msg) { + print "$msg\n\n"; } print < "../koha_$newversion.orig.tar.gz"} ); + sys_command_output( + qq{git archive --format=tar --prefix="koha-$newversion/" HEAD | gzip -9 > "../koha_$newversion.orig.tar.gz"}); - my $pdebuildopts = $buildresult ? "--buildresult $buildresult" : ""; - my $pdebuildbasetgz = $basetgz ? "-- --use-network yes --basetgz /var/cache/pbuilder/" . $basetgz . ".tgz" : ""; - sys_command_output_screen( "pdebuild $pdebuildbasetgz $pdebuildopts" ); + my $pdebuildopts = $buildresult ? "--buildresult $buildresult" : ""; + my $pdebuildbasetgz = $basetgz ? "-- --use-network yes --basetgz /var/cache/pbuilder/" . $basetgz . ".tgz" : ""; + sys_command_output_screen("pdebuild --debbuildopts -sa $pdebuildbasetgz $pdebuildopts"); } -everything_is_committed() or die "cannot build: uncommited changes"; +everything_is_committed() or die "cannot build: uncommitted changes"; -my $newversion = $auto_version - ? sprintf ('%s%s.%s', $version, strftime("+%Y%m%d%H%M%S", localtime), latest_sha1()) - : $version; +my $newversion = + $auto_version + ? sprintf( '%s%s.%s', $version, strftime( "+%Y%m%d%H%M%S", localtime ), latest_sha1() ) + : $version; -adjust_debian_changelog( $newversion ); -build_package( $newversion ); +adjust_debian_changelog($newversion) if $auto_changelog; +build_package($newversion); reset_debian_changelog(); diff --git a/debian/control b/debian/control index 9ff48a08aa..1e13743535 100644 --- a/debian/control +++ b/debian/control @@ -137,6 +137,7 @@ Build-Depends: libalgorithm-checkdigits-perl, libtemplate-plugin-gettext-perl, libtemplate-plugin-htmltotext-perl, libtemplate-plugin-json-escape-perl, + libtemplate-plugin-json-perl, libtemplate-plugin-stash-perl, libtest-deep-perl, libtest-exception-perl, @@ -370,6 +371,7 @@ Depends: libalgorithm-checkdigits-perl, libpdf-table-perl, libplack-middleware-logwarn-perl, libplack-middleware-reverseproxy-perl, + libpod-coverage-perl, libreadonly-perl, libscalar-list-utils-perl, libschedule-at-perl, @@ -386,6 +388,7 @@ Depends: libalgorithm-checkdigits-perl, libtemplate-plugin-gettext-perl, libtemplate-plugin-htmltotext-perl, libtemplate-plugin-json-escape-perl, + libtemplate-plugin-json-perl, libtemplate-plugin-stash-perl, libtest-deep-perl, libtest-exception-perl, diff --git a/debian/templates/koha-conf-site.xml.in b/debian/templates/koha-conf-site.xml.in index 1f034a26c5..afc23a98cc 100644 --- a/debian/templates/koha-conf-site.xml.in +++ b/debian/templates/koha-conf-site.xml.in @@ -474,11 +474,9 @@ __END_SRU_PUBLICSERVER__ __KEEP_COOKIE__ - catalogue_editor_\d+ - diff --git a/debian/templates/zebra-authorities-dom-site.cfg.in b/debian/templates/zebra-authorities-dom-site.cfg.in index be2e0c3ae6..01d446b8d6 100644 --- a/debian/templates/zebra-authorities-dom-site.cfg.in +++ b/debian/templates/zebra-authorities-dom-site.cfg.in @@ -8,7 +8,7 @@ profilePath:/etc/koha/sites/__KOHASITE__:/etc/koha/zebradb/authorities/etc:/etc/ encoding: UTF-8 # modulePath - where to look for loadable zebra modules -modulePath: /usr/lib/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules:/usr/lib/i386-linux-gnu/idzebra-2.0/modules:/usr/lib/aarch64-linux-gnu/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabi/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabihf/idzebra-2.0/modules:/usr/lib/mips-linux-gnu/idzebra-2.0/modules:/usr/lib/mipsel-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc64le-linux-gnu/idzebra-2.0/modules:/usr/lib/s390x-linux-gnu/idzebra-2.0/modules +modulePath: /usr/lib64/idzebra-2.0/modules:/usr/lib/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules:/usr/lib/i386-linux-gnu/idzebra-2.0/modules:/usr/lib/aarch64-linux-gnu/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabi/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabihf/idzebra-2.0/modules:/usr/lib/mips-linux-gnu/idzebra-2.0/modules:/usr/lib/mipsel-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc64le-linux-gnu/idzebra-2.0/modules:/usr/lib/s390x-linux-gnu/idzebra-2.0/modules # Files that describe the attribute sets supported. attset: bib1.att diff --git a/debian/templates/zebra-biblios-dom-site.cfg.in b/debian/templates/zebra-biblios-dom-site.cfg.in index 7b5e52c153..29bf9a8473 100644 --- a/debian/templates/zebra-biblios-dom-site.cfg.in +++ b/debian/templates/zebra-biblios-dom-site.cfg.in @@ -5,7 +5,7 @@ # Where are the config files located? profilePath:/etc/koha/sites/__KOHASITE__:/etc/koha/zebradb/biblios/etc:/etc/koha/zebradb/etc:/etc/koha/zebradb/marc_defs/__ZEBRA_MARC_FORMAT__/biblios:/etc/koha/zebradb/lang_defs/__ZEBRA_LANGUAGE__:/etc/koha/zebradb/xsl # modulePath - where to look for loadable zebra modules -modulePath: /usr/lib/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules:/usr/lib/i386-linux-gnu/idzebra-2.0/modules:/usr/lib/aarch64-linux-gnu/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabi/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabihf/idzebra-2.0/modules:/usr/lib/mips-linux-gnu/idzebra-2.0/modules:/usr/lib/mipsel-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc64le-linux-gnu/idzebra-2.0/modules:/usr/lib/s390x-linux-gnu/idzebra-2.0/modules +modulePath: /usr/lib64/idzebra-2.0/modules:/usr/lib/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules:/usr/lib/i386-linux-gnu/idzebra-2.0/modules:/usr/lib/aarch64-linux-gnu/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabi/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabihf/idzebra-2.0/modules:/usr/lib/mips-linux-gnu/idzebra-2.0/modules:/usr/lib/mipsel-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc64le-linux-gnu/idzebra-2.0/modules:/usr/lib/s390x-linux-gnu/idzebra-2.0/modules encoding: UTF-8 # Files that describe the attribute sets supported. diff --git a/docs/teams.yaml b/docs/teams.yaml index 5233e291ad..37a984fdf2 100644 --- a/docs/teams.yaml +++ b/docs/teams.yaml @@ -573,8 +573,8 @@ team: translation: name: Bernardo González Kriegel packaging: - name: Mirko Tietgen - name: Mason James + - name: Mirko Tietgen + - name: Mason James ci: - name: Tomás Cohen Arazi maintainer: @@ -624,8 +624,8 @@ team: translation: name: Bernardo González Kriegel packaging: - name: Mirko Tietgen - name: Mason James + - name: Mirko Tietgen + - name: Mason James (17.05) ci: - name: Tomás Cohen Arazi maintainer: @@ -680,8 +680,8 @@ team: - name: Indranil Das Gupta - name: Bernardo González Kriegel packaging: - name: Mirko Tietgen - name: Mason James + - name: Mirko Tietgen + - name: Mason James ci: - name: Tomás Cohen Arazi - name: Jonathan Druart @@ -1008,6 +1008,8 @@ team: name: Owen Leonard - area: Accounts name: Martin Renvoize + - area: Elasticsearch + name: Fridolin Somers - area: Zebra name: Fridolin Somers bugwrangler: @@ -1027,6 +1029,8 @@ team: - name: Mason James ci: - name: Mason James + wiki: + - name: Thomas Dukleth accessibility_advocates: - name: Henry Bolshaw - name: Wainui Witika-Park @@ -1050,16 +1054,16 @@ team: qa_manager: name: Katrin Fischer qa: - - name: Tomás Cohen Arazi - - name: Nick Clemens + - name: Andrew Nugged - name: Jonathan Druart - - name: Victor Grousset - - name: Kyle M Hall - name: Joonas Kylmälä - - name: Andrew Nugged - - name: Martin Renvoize + - name: Kyle M Hall - name: Marcel de Rooy + - name: Martin Renvoize + - name: Nick Clemens - name: Petro Vashchuk + - name: Tomás Cohen Arazi + - name: Victor Grousset te: - area: UI Design name: Owen Leonard @@ -1076,11 +1080,11 @@ team: name: David Nind documentation_team: - name: Aude Charillon - - name: Rocio Lopez - - name: Kelly McElligott - - name: Martin Renvoize - name: Caroline Cyr La Rose + - name: Kelly McElligott - name: Lucy Vaux-Harvey + - name: Martin Renvoize + - name: Rocio Lopez meeting_facilitator: - name: Jessica Zairo translations: @@ -1126,6 +1130,7 @@ team: - name: Marcel de Rooy - name: Fridolin Somers - name: Petro Vashchuk + - name: David Cook te: - area: UI Design name: Owen Leonard @@ -1193,9 +1198,7 @@ team: - area: REST API name: Martin Renvoize - area: ERM - name: Pedro Amorim - - area: ERM - name: Agustín Moyano + name: Pedro Amorim, Agustín Moyano bugwrangler: - name: Aleisha Amohia - name: Indranil Das Gupta @@ -1243,17 +1246,17 @@ team: name: Katrin Fischer qa: - name: Aleisha Amohia - - name: Nick Clemens + - name: Andrii Nugged - name: David Cook + - name: Emily Lamancusa - name: Jonathan Druart - - name: Lucas Gass - - name: Victor Grousset - name: Kyle M Hall - - name: Emily Lamancusa - - name: Andrii Nugged - - name: Martin Renvoize + - name: Lucas Gass - name: Marcel de Rooy + - name: Martin Renvoize + - name: Nick Clemens - name: Petro Vashchuk + - name: Victor Grousset te: - area: UI Design name: Owen Leonard @@ -1363,9 +1366,10 @@ team: ktd: - name: Tomás Cohen Arazi wiki: - - name: Thomas Dukleth - name: George Williams + - name: Katrin Fischer - name: Mason James + - name: Thomas Dukleth website: - name: Liz Rea newsletter: @@ -1390,23 +1394,23 @@ team: qa_manager: name: Martin Renvoize qa: - - name: Marcel de Rooy - - name: Kyle M Hall - - name: Emily Lamancusa - - name: Nick Clemens - - name: Lucas Gass - - name: Tomás Cohen Arazi - - name: Julian Maurice - - name: Victor Grousset - name: Aleisha Amohia + - name: Chris Cormack - name: David Cook - - name: Laura Escamilla + - name: Emily Lamancusa - name: Jonathan Druart - - name: Pedro Amorim + - name: Julian Maurice + - name: Kyle M Hall + - name: Laura Escamilla + - name: Lucas Gass + - name: Marcel de Rooy - name: Matt Blenkinsop - - name: Thomas Klausner + - name: Nick Clemens - name: Paul Derscheid - - name: Chris Cormack + - name: Pedro Amorim + - name: Thomas Klausner + - name: Tomás Cohen Arazi + - name: Victor Grousset te: - area: UI Design name: Owen Leonard @@ -1463,33 +1467,38 @@ team: - version: 24.11 name: Paul Derscheid - version: 24.05 - name: Wainui Witika-Park + name: Catalyst (Wainui Witika-Park, Alex Buckley, Aleisha Amoha) - version: 23.11 name: Fridolin Somers - version: 22.11 - - name: Laura Escamilla + name: Jesse Maseto qa_manager: name: Martin Renvoize qa: - - name: Victor Grousset - - name: Lisette Scheer - - name: Emily Lamancusa + - name: Aleisha Amohia + - name: Baptiste Wojtowski + - name: Brendan Lawlor - name: David Cook + - name: David Nind + - name: Emily Lamancusa - name: Jonathan Druart - name: Julian Maurice - - name: Baptiste Wojtowski - - name: Paul Derscheid - - name: Aleisha Amohia - - name: Laura Escamilla - - name: Tomás Cohen Arazi - name: Kyle M Hall - - name: Nick Clemens + - name: Laura Escamilla + - name: Lisette Scheer - name: Lucas Gass + - name: Magnus Enger - name: Marcel de Rooy + - name: Martin Renvoize - name: Matt Blenkinsop + - name: Nick Clemens + - name: Owen Leonard + - name: Paul Derscheid - name: Pedro Amorim - - name: Brendan Lawlor - name: Thomas Klausner + - name: Tomás Cohen Arazi + - name: Victor Grousset + - name: Wainui Witika-Park security_manager: - name: Tomás Cohen Arazi te: @@ -1508,7 +1517,7 @@ team: documentation_team: - name: Aude Charillon - name: David Nind - - name: Caroline Cyr La Rose + - name: Caroline Cyr la Rose translation: name: Jonathan Druart meeting_facilitator: @@ -1531,3 +1540,65 @@ team: - name: Lauren Purton newsletter: name: Michael Kuhn + accessibility_advocate: + name: David Nind + 25.11: + release_date: 1763855999 + manager: + name: Lucas Gass + maintainer: + - version: 25.05 + name: Paul Derscheid + - version: 24.11 + name: Fridolin Somers + - version: 24.05 + name: Jesse Maseto + - version: 22.11 + name: "Catalyst IT (Wainui, Alex, Aleisha)" + maintainer_assistants: + - version: 25.05 + name: Martin Renvoize + - version: 24.11 + name: Baptiste Wojtkowski + - version: 24.05 + name: Laura Escamilla + qa_manager: + name: Martin Renvoize + qa: + - name: Andrew Fuerste-Henry + - name: Andrii Nugged + - name: Baptiste Wojtkowski + - name: Brendan Lawlor + - name: David Cook + - name: Emily Lamancusa + - name: Jonathan Druart + - name: Julian Maurice + - name: Kyle Hall + - name: Laura Escamilla + - name: Lisette Scheer + - name: Marcel de Rooy + - name: Nick Clemens + - name: Paul Derscheid + - name: Petro V + - name: Tomás Cohen Arazi + - name: Victor Grousset + documentation: + name: David Nind + documentation_team: + - name: Aude Charillon + - name: Caroline Cyr La Rose + - name: Donna Bachowski + - name: Heather Hernandez + - name: Kristi Krueger + - name: Philip Orr + translation: + name: Jonathan Druart + website: + name: David Nind + wiki: + - name: George Williams + - name: Thomas Dukleth + social_media: + name: David Nind + newsletter: + name: Michael Kuhn diff --git a/etc/koha-conf.xml b/etc/koha-conf.xml index b162219f9c..33768161a2 100644 --- a/etc/koha-conf.xml +++ b/etc/koha-conf.xml @@ -285,11 +285,9 @@ 1 - catalogue_editor_\d+ - diff --git a/etc/zebradb/zebra-authorities-dom.cfg b/etc/zebradb/zebra-authorities-dom.cfg index f3b267b4fe..f1b5a6a9e1 100644 --- a/etc/zebradb/zebra-authorities-dom.cfg +++ b/etc/zebradb/zebra-authorities-dom.cfg @@ -8,7 +8,7 @@ profilePath:__ZEBRA_CONF_DIR__/authorities/etc:__ZEBRA_CONF_DIR__/etc:__ZEBRA_CO encoding: UTF-8 # modulePath - where to look for loadable zebra modules -modulePath: /usr/lib/idzebra-2.0/modules:/usr/lib64/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules/ +modulePath: /usr/lib64/idzebra-2.0/modules:/usr/lib/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules:/usr/lib/i386-linux-gnu/idzebra-2.0/modules:/usr/lib/aarch64-linux-gnu/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabi/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabihf/idzebra-2.0/modules:/usr/lib/mips-linux-gnu/idzebra-2.0/modules:/usr/lib/mipsel-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc64le-linux-gnu/idzebra-2.0/modules:/usr/lib/s390x-linux-gnu/idzebra-2.0/modules # Files that describe the attribute sets supported. attset: bib1.att diff --git a/etc/zebradb/zebra-biblios-dom.cfg b/etc/zebradb/zebra-biblios-dom.cfg index 76ed216990..494666e82c 100644 --- a/etc/zebradb/zebra-biblios-dom.cfg +++ b/etc/zebradb/zebra-biblios-dom.cfg @@ -5,7 +5,7 @@ # Where are the config files located? profilePath:__ZEBRA_CONF_DIR__/biblios/etc:__ZEBRA_CONF_DIR__/etc:__ZEBRA_CONF_DIR__/marc_defs/__ZEBRA_MARC_FORMAT__/biblios:__ZEBRA_CONF_DIR__/lang_defs/__ZEBRA_LANGUAGE__:__ZEBRA_CONF_DIR__/xsl # modulePath - where to look for loadable zebra modules -modulePath: /usr/lib/idzebra-2.0/modules:/usr/lib64/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules/ +modulePath: /usr/lib64/idzebra-2.0/modules:/usr/lib/idzebra-2.0/modules:/usr/lib/x86_64-linux-gnu/idzebra-2.0/modules:/usr/lib/i386-linux-gnu/idzebra-2.0/modules:/usr/lib/aarch64-linux-gnu/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabi/idzebra-2.0/modules:/usr/lib/arm-linux-gnueabihf/idzebra-2.0/modules:/usr/lib/mips-linux-gnu/idzebra-2.0/modules:/usr/lib/mipsel-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc-linux-gnu/idzebra-2.0/modules:/usr/lib/powerpc64le-linux-gnu/idzebra-2.0/modules:/usr/lib/s390x-linux-gnu/idzebra-2.0/modules encoding: UTF-8 # Files that describe the attribute sets supported. diff --git a/ill/ill-requests.pl b/ill/ill-requests.pl index 0db9c09b1e..8bb8c255c6 100755 --- a/ill/ill-requests.pl +++ b/ill/ill-requests.pl @@ -117,7 +117,7 @@ if ($backends_available) { $template->param( notices => $notices, request => $request, - ( $params->{tran_error} ? ( tran_error => $params->{tran_error} ) : () ), + ( $params->{tran_fail} ? ( tran_fail => $params->{tran_fail} ) : () ), ( $params->{tran_success} ? ( tran_success => $params->{tran_success} ) : () ), ); @@ -478,7 +478,7 @@ if ($backends_available) { $append .= '&tran_success=' . join( ',', @{ $ret->{result}->{success} } ); } if ( $ret->{result} && scalar @{ $ret->{result}->{fail} } > 0 ) { - $append .= '&tran_fail=' . join( ',', @{ $ret->{result}->{fail} } . join(',') ); + $append .= '&tran_fail=' . join( ',', @{ $ret->{result}->{fail} } ); } # Redirect to view the whole request diff --git a/installer/data/mysql/db_revs/250600001.pl b/installer/data/mysql/db_revs/250600001.pl new file mode 100755 index 0000000000..f279bd5021 --- /dev/null +++ b/installer/data/mysql/db_revs/250600001.pl @@ -0,0 +1,20 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "23010", + description => "Add new PreventWithdrawingItemsStatus system preference", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + $dbh->do( + q{ + INSERT IGNORE INTO systempreferences (`variable`,`value`,`options`,`explanation`,`type`) + VALUES ('PreventWithdrawingItemsStatus','','','Prevent the withdrawing of items based on statuses','multiple') + } + ); + + say_success( $out, "Added new system preference 'PreventWithdrawingItemsStatus'" ); + }, +}; diff --git a/installer/data/mysql/db_revs/250600002.pl b/installer/data/mysql/db_revs/250600002.pl new file mode 100755 index 0000000000..078ce54072 --- /dev/null +++ b/installer/data/mysql/db_revs/250600002.pl @@ -0,0 +1,40 @@ +use Modern::Perl; + +return { + bug_number => "34563", + description => "Move StaffReportsHomeHTML to HTML customizations", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + # Get any existing value from the IntranetReportsHomeHTML system preference + my ($staffreportshome) = $dbh->selectrow_array( + q| + SELECT value FROM systempreferences WHERE variable='IntranetReportsHomeHTML'; + | + ); + if ($staffreportshome) { + + $dbh->do( + "INSERT INTO additional_contents ( category, code, location, branchcode, published_on ) VALUES ('html_customizations', 'StaffReportsHome', 'StaffReportsHome', NULL, CAST(NOW() AS date) )" + ); + + my ($insert_id) = $dbh->selectrow_array( + "SELECT id FROM additional_contents WHERE category = 'html_customizations' AND code = 'StaffReportsHome' AND location = 'StaffReportsHome' LIMIT 1", + {} + ); + + $dbh->do( + "INSERT INTO additional_contents_localizations ( additional_content_id, title, content, lang ) VALUES ( ?, 'StaffReportsHome default', ?, 'default' )", + undef, $insert_id, $staffreportshome + ); + + say $out "Added 'StaffReportsHome' HTML customization"; + } + + # Remove old system preference + $dbh->do("DELETE FROM systempreferences WHERE variable='IntranetReportsHomeHTML'"); + say $out "Removed system preference 'IntranetReportsHomeHTML'"; + + }, +}; diff --git a/installer/data/mysql/db_revs/250600003.pl b/installer/data/mysql/db_revs/250600003.pl new file mode 100755 index 0000000000..951097d56d --- /dev/null +++ b/installer/data/mysql/db_revs/250600003.pl @@ -0,0 +1,32 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "40337", + description => "Define checkprevcheckout as ENUM", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + $dbh->do( + q{ + ALTER TABLE borrowers + MODIFY COLUMN `checkprevcheckout` enum('yes', 'no', 'inherit') NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to category setting if ''inherit''.' + } + ); + + $dbh->do( + q{ + ALTER TABLE categories + MODIFY COLUMN `checkprevcheckout` enum('yes', 'no', 'inherit') NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron category if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to syspref setting if ''inherit''.' + } + ); + + $dbh->do( + q{ + ALTER TABLE deletedborrowers + MODIFY COLUMN `checkprevcheckout` enum('yes', 'no', 'inherit') NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to category setting if ''inherit''.' + } + ); + }, +}; diff --git a/installer/data/mysql/db_revs/250600004.pl b/installer/data/mysql/db_revs/250600004.pl new file mode 100755 index 0000000000..7f871c7388 --- /dev/null +++ b/installer/data/mysql/db_revs/250600004.pl @@ -0,0 +1,22 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "36947", + description => "Add FacetSortingLocale system preference for locale-based facet sorting", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + $dbh->do( + q{ + INSERT IGNORE INTO systempreferences (`variable`,`value`,`options`,`explanation`,`type`) + VALUES ('FacetSortingLocale','default','', + 'Choose the locale for sorting facet names when FacetOrder is set to Alphabetical. This enables proper Unicode-aware sorting of accented characters and locale-specific alphabetical ordering.', + 'Choice') + } + ); + + say_success( $out, "Added new system preference 'FacetSortingLocale'" ); + }, +}; diff --git a/installer/data/mysql/en/optional/sample_news.yml b/installer/data/mysql/en/optional/sample_news.yml index 988d927005..39432d9d7d 100644 --- a/installer/data/mysql/en/optional/sample_news.yml +++ b/installer/data/mysql/en/optional/sample_news.yml @@ -80,12 +80,12 @@ tables: content: - "Now that you've installed Koha, what's next? Here are some suggestions:" - "" - "" lang: "default" diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 5d7139383c..a9537d2150 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -1598,7 +1598,7 @@ CREATE TABLE `borrowers` ( `privacy` int(11) NOT NULL DEFAULT 1 COMMENT 'patron/borrower''s privacy settings related to their checkout history', `privacy_guarantor_fines` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'controls if relatives can see this patron''s fines', `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'controls if relatives can see this patron''s checkouts', - `checkprevcheckout` varchar(7) NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to category setting if ''inherit''.', + `checkprevcheckout` enum('yes', 'no', 'inherit') NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to category setting if ''inherit''.', `updated_on` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT 'time of last change could be useful for synchronization with external systems (among others)', `lastseen` datetime DEFAULT NULL COMMENT 'last time a patron has been seen (connected at the OPAC or staff interface)', `lang` varchar(25) NOT NULL DEFAULT 'default' COMMENT 'lang to use to send notices to this patron', @@ -1808,7 +1808,7 @@ CREATE TABLE `categories` ( `category_type` varchar(1) NOT NULL DEFAULT 'A' COMMENT 'type of Koha patron (Adult, Child, Professional, Organizational, Statistical, Staff)', `BlockExpiredPatronOpacActions` varchar(128) NOT NULL DEFAULT 'follow_syspref_BlockExpiredPatronOpacActions' COMMENT 'specific actions expired patrons of this category are blocked from performing or if the BlockExpiredPatronOpacActions system preference is to be followed', `default_privacy` enum('default','never','forever') NOT NULL DEFAULT 'default' COMMENT 'Default privacy setting for this patron category', - `checkprevcheckout` varchar(7) NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron category if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to syspref setting if ''inherit''.', + `checkprevcheckout` enum('yes', 'no', 'inherit') NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron category if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to syspref setting if ''inherit''.', `can_place_ill_in_opac` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'can this patron category place interlibrary loan requests', `can_be_guarantee` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'if patrons of this category can be guarantees', `reset_password` tinyint(1) DEFAULT NULL COMMENT 'if patrons of this category can do the password reset flow,', @@ -2760,7 +2760,7 @@ CREATE TABLE `deletedborrowers` ( `privacy` int(11) NOT NULL DEFAULT 1 COMMENT 'patron/borrower''s privacy settings related to their checkout history KEY `borrowernumber` (`borrowernumber`),', `privacy_guarantor_fines` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'controls if relatives can see this patron''s fines', `privacy_guarantor_checkouts` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'controls if relatives can see this patron''s checkouts', - `checkprevcheckout` varchar(7) NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to category setting if ''inherit''.', + `checkprevcheckout` enum('yes', 'no', 'inherit') NOT NULL DEFAULT 'inherit' COMMENT 'produce a warning for this patron if this item has previously been checked out to this patron if ''yes'', not if ''no'', defer to category setting if ''inherit''.', `updated_on` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT 'time of last change could be useful for synchronization with external systems (among others)', `lastseen` datetime DEFAULT NULL COMMENT 'last time a patron has been seen (connected at the OPAC or staff interface)', `lang` varchar(25) NOT NULL DEFAULT 'default' COMMENT 'lang to use to send notices to this patron', @@ -5772,6 +5772,19 @@ CREATE TABLE `saved_reports` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; +DROP TABLE IF EXISTS `reports_branches`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `reports_branches` ( + `report_id` int(11) NOT NULL, + `branchcode` varchar(10) NOT NULL, + KEY `report_id` (`report_id`), + KEY `branchcode` (`branchcode`), + CONSTRAINT `reports_branches_ibfk_1` FOREIGN KEY (`report_id`) REFERENCES `saved_sql` (`id`) ON DELETE CASCADE, + CONSTRAINT `reports_branches_ibfk_2` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `saved_sql` -- diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index 09b8afd6fd..f2b6d940cc 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -278,6 +278,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('FacetLabelTruncationLength','20',NULL,'Specify the facet max length in OPAC','Integer'), ('FacetMaxCount','20',NULL,'Specify the max facet count for each category','Integer'), ('FacetOrder','Alphabetical','Alphabetical|Usage','Specify the order of facets within each category','Choice'), +('FacetSortingLocale','default','','Choose the locale for sorting facet names when FacetOrder is set to Alphabetical. This enables proper Unicode-aware sorting of accented characters and locale-specific alphabetical ordering.','Choice'), ('FailedLoginAttempts','','','Number of login attempts before lockout the patron account','Integer'), ('FallbackToSMSIfNoEmail', 0, 'Enable|Disable', 'Send messages by SMS if no patron email is defined', 'YesNo'), ('FeeOnChangePatronCategory','1','','If set, when a patron changes to a category with enrolment fee, a fee is charged','YesNo'), @@ -357,7 +358,6 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('IntranetNumbersPreferPhrase','0',NULL,'Control the use of phr operator in callnumber and standard number staff interface searches','YesNo'), ('intranetreadinghistory','1','','If ON, Checkout history is enabled for all patrons','YesNo'), ('IntranetReadingHistoryHolds', 1, '', 'If ON, Holds history is enabled for all patrons','YesNo'), -('IntranetReportsHomeHTML', '', NULL, 'Show the following HTML in a div on the bottom of the reports home page', 'Free'), ('IntranetSlipPrinterJS','','','Use this JavaScript for printing slips. Define at least function printThenClose(). For use e.g. with Firefox PlugIn jsPrintSetup, see http://jsprintsetup.mozdev.org/','Free'), ('intranetstylesheet','','50','Enter a complete URL to use an alternate layout stylesheet in Intranet','free'), ('IntranetUserCSS','',NULL,'Add CSS to be included in the intranet in an embedded [% INCLUDE 'header.inc' %] @@ -801,11 +806,7 @@ [% IF db_audit.diff_found %]
-

Run the following SQL to fix the database:

-
-                    [% db_audit.diff | $raw %]
-                
+
[% db_audit.diff | html %]
[% END %] [% END # tab=database %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt index 49c9d98fd3..8561c5fe75 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/basket.tt @@ -150,6 +150,8 @@ class="btn btn-default btn-xs submit-form-link" href="#" data-ean="[% eanacct.ean | html %]" + data-ean_description="[% eanacct.description | html %]" + data-ean_branch="[% eanacct.branch.branchname | html %]" data-basketno="[% basketno | html %]" data-action="basket.pl" data-method="post" @@ -812,6 +814,19 @@ Modify
Transfer +
+ [% END %] + [% UNLESS ( books_loo.suggestionid ) %] + [% tp('verb', 'Link suggestion') | html %] [% END %] [% END %] @@ -1015,7 +1030,11 @@
[% INCLUDE 'csrf-token.inc' %] -

Are you sure you want to generate an EDIFACT order and close basket [% basketname | html %]?

+

Are you sure you want to generate this EDIFACT order?

+
    +
  • An EDIFACT order will be generated for [% ean_branch | html %] ([% ean | html %]) [% IF ean_description %][% ean_description | html %][% END %]
  • +
  • The basket [% basketname | html %] will be closed
  • +
[% IF CAN_user_acquisition_group_manage %]

@@ -1028,11 +1047,11 @@ - +

- +
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/newordersuggestion.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/newordersuggestion.tt index 613b56588b..a598e9d822 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/newordersuggestion.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/newordersuggestion.tt @@ -89,7 +89,20 @@ [% suggestion.total | $Price %] - [% IF ( suggestion.biblionumber ) %] + [% IF link_order %] + [% tp('verb', 'Link suggestion') | html %] + [% ELSIF ( suggestion.biblionumber ) %] Checkout charge limit: [%- SET pref_noissuescharge_link = 'noissuescharge' -%] -
If set, this will override the global value set in the [%- pref_noissuescharge_link | $raw | $KohaSpan -%] preference.
+
If set, this will override the global value set in the [%- pref_noissuescharge_link | $raw | $KohaSpan -%] system preference.
  • [%- SET pref_NoIssuesChargeGuarantees_link = 'NoIssuesChargeGuarantees' -%] -
    If set, this will override the global value set in the [%- pref_NoIssuesChargeGuarantees_link | $raw | $KohaSpan -%] preference.
    +
    If set, this will override the global value set in the [%- pref_NoIssuesChargeGuarantees_link | $raw | $KohaSpan -%] system preference.
  • @@ -505,8 +505,8 @@ size="5" maxlength="8" /> - [%- SET pref_NoIssuesChargeGuarantorsWithGuarantees_link = 'NoIssuesChargeGuarantees' -%] -
    If set, this will override the global value set in the [%- pref_NoIssuesChargeGuarantorsWithGuarantees_link | $raw | $KohaSpan -%] preference.
    + [%- SET pref_NoIssuesChargeGuarantorsWithGuarantees_link = 'NoIssuesChargeGuarantorsWithGuarantees' -%] +
    If set, this will override the global value set in the [%- pref_NoIssuesChargeGuarantorsWithGuarantees_link | $raw | $KohaSpan -%] system preference.
  • diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt index 199502cdaf..e49f2ac527 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt @@ -198,11 +198,12 @@ $(document).ready(function() { $(".dialog").hide(); - var table = $("#localization").kohaTable({ + let table = $("#localization").kohaTable({ dom: "t", paging: false, autoWidth: false, }); + let table_dt = table.DataTable(); var languages_select = $(''); [% FOR language IN languages %] @@ -275,7 +276,7 @@ if ( success.error ) { show_message({ type: 'error_on_insert', data: success }); } else { - var new_row = table.row.add( [ success.id, success.entity, success.code, success.lang, success.translation, " Delete" ] ).draw().node(); + var new_row = table_dt.row.add( [ success.id, success.entity, success.code, success.lang, success.translation, " Delete" ] ).draw().node(); $( new_row ).attr("id", "row_id_" + success.id ).data("id", success.id ); show_message({ type: 'success_on_insert', data: success }); } diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/marctagstructure.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/marctagstructure.tt index f307644d51..5bdc3777c9 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/marctagstructure.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/marctagstructure.tt @@ -94,7 +94,9 @@ [% IF ( else ) %]
    New tag - Edit framework + [% IF framework %] + Edit framework + [% END %]
    [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref index 523c30b896..7f1a886095 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/acquisitions.pref @@ -9,7 +9,7 @@ Acquisitions: cataloguing: cataloging the record. - This is only the default behavior, and can be changed per-basket. - - - "The following database columns should be unique in an item:" + - "The following database columns should be unique in an item:" - pref: UniqueItemFields type: modalselect source: items diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref index 9719f3c87e..9cd73cfe85 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -677,6 +677,13 @@ Circulation: 1: Block 0: "Don't block" - returning of items that have been withdrawn. + - + - "Prevent the ability to withdraw items with the following statuses:" + - pref: PreventWithdrawingItemsStatus + multiple: + intransit: In-transit + checkedout: Checked out + - - - pref: BlockReturnOfLostItems choices: @@ -1527,4 +1534,4 @@ Circulation: choices: 1: Enable 0: Disable - - "the curbside pickup module." + - "the curbside pickup module." \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/i18n_l10n.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/i18n_l10n.pref index 34a9d54211..e95b345434 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/i18n_l10n.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/i18n_l10n.pref @@ -63,6 +63,11 @@ I18N/L10N: de: German style ([Address] [Street number] - [ZIP/Postal Code] [City] - [Country]) fr: French style ([Street number] [Address] - [ZIP/Postal Code] [City] - [Country]) - . + - + - Sort facet names using + - pref: FacetSortingLocale + type: locale-list + - locale when FacetOrder is set to Alphabetical. This enables proper Unicode-aware sorting of accented characters and locale-specific alphabetical ordering. - - pref: TranslateNotices choices: diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref index 5441fd7e11..f15aad0b93 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref @@ -668,7 +668,7 @@ OPAC: type: textarea syntax: text/x-yaml class: code - - Define custom rules to hide specific items from search and view on the OPAC. How to write these rules is documented on the Koha wiki. + - Define custom rules to hide specific items from search and view on the OPAC. How to write these rules is documented on the Koha wiki. - - 'List of patron categories, that can see items otherwise hidden by OpacHiddenItems:' - pref: OpacHiddenItemsExceptions @@ -851,19 +851,19 @@ OPAC: - "days after account creation." - "
    NOTE: This system preference requires the misc/cronjobs/cleanup_database.pl cronjob. Ask your system administrator to schedule it.
    No patrons will be deleted if you set the pref to zero or make it empty." - - - "The following database columns must be filled in on the patron modification screen:" + - "The following database columns must be filled in on the patron modification screen:" - pref: PatronSelfModificationMandatoryField type: modalselect source: borrowers exclusions: password|cardnumber|dateexpiry|categorycode|sort1|sort2|opacnote|borrowernotes|gonenoaddress|lost|flags - - - "The following database columns must be filled in on the patron entry screen:" + - "The following database columns must be filled in on the patron entry screen:" - pref: PatronSelfRegistrationBorrowerMandatoryField type: modalselect source: borrowers exclusions: sort1|sort2|opacnote|borrowernotes|gonenoaddress|lost|flags - - - "The following database columns will not appear on the patron self-registration screen:" + - "The following database columns will not appear on the patron self-registration screen:" - pref: PatronSelfRegistrationBorrowerUnwantedField type: modalselect source: borrowers @@ -871,7 +871,7 @@ OPAC: inclusions: categorycode|dateexpiry - '
    NOTE: preferred_name will be set to firstname if not included in the form.' - - - "The following database columns will not appear on the patron self-modification screen:" + - "The following database columns will not appear on the patron self-modification screen:" - pref: PatronSelfModificationBorrowerUnwantedField type: modalselect source: borrowers diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref index 424b3eee9b..2ca8899ec3 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref @@ -211,7 +211,7 @@ Patrons: - pref: EmailFieldPrecedence class: multi - '
    NOTE: All patron fields can be used, but to work correctly they must contain a valid email address or an empty string.' - - "Valid options are the database columns of the borrowers table, separated by | (pipe)." + - "Valid options are the database columns of the borrowers table, separated by | (pipe)." - "Example: email|emailpro|B_email" - - "When EmailFieldPrimary is set to 'selected addresses', send email to all valid email addresses in the selected fields:" @@ -274,14 +274,14 @@ Patrons: cron: (Deprecated) according to --send-notices cron switch Patron forms: - - - "The following database columns must be filled in on the patron entry screen:" + - "The following database columns must be filled in on the patron entry screen:" - pref: BorrowerMandatoryField type: modalselect source: borrowers exclusions: flags - 'NOTE: If autoMemberNum is enabled, the system preference BorrowerMandatoryField must not contain the field cardnumber.' - - - "The following database columns will not appear on the patron entry screen:" + - "The following database columns will not appear on the patron entry screen:" - pref: BorrowerUnwantedField type: modalselect source: borrowers @@ -311,7 +311,7 @@ Patrons: 0: "Don't" - store and display surnames in upper case. - - - "The following database columns:" + - "The following database columns:" - pref: PatronQuickAddFields type: modalselect source: borrowers @@ -337,7 +337,7 @@ Patrons: messaging: "Patron messaging preferences" - . - - - "The following database columns:" + - "The following database columns:" - pref: PatronDuplicateMatchingAddFields type: modalselect source: borrowers diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/reports.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/reports.pref new file mode 100644 index 0000000000..1579aaf090 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/reports.pref @@ -0,0 +1,9 @@ +Reports: + Reports Access: + - + - pref: EnableFilteringReports + choices: + 1: Enable + 0: Disable + - "filtering report access based on staff home library." + - "
    NOTE: A NOTE ABOUT THE EFFECTS OF THIS PREFERENCE / SETTING" \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref index 8da36fceb1..00b1b06912 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref @@ -113,12 +113,6 @@ Staff interface: type: textarea syntax: text/html class: code - - - - "Show the following HTML in its own div on the bottom of the home page of the reports module:" - - pref: IntranetReportsHomeHTML - type: textarea - syntax: text/html - class: code - - pref: StaffHighlightedWords type: boolean diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/search_filters.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/search_filters.tt index f822751a8f..1aea30fc4e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/search_filters.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/search_filters.tt @@ -30,11 +30,9 @@ [% END #/ WRAPPER sub-header.inc %] [% WRAPPER 'main-container.inc' aside='admin-menu' %] - +

    Search filters

    [% IF filters_count %] -
    -

    Search filters

    - +
    @@ -44,7 +42,7 @@ - +
    Limits OPAC Staff interface Actions
    @@ -62,14 +60,16 @@