From 03320d4d412fd5ceb7f83117079d9cd781fbbcdc Mon Sep 17 00:00:00 2001 From: Jake Deery Date: Mon, 1 Dec 2025 13:15:02 +0000 Subject: [PATCH] Bug 14962: On Display code for existing Koha modules This patch adds code for the On Display module, found in the existing Koha modules. Please see the test files commit for instructions on how to test this bundle of patches. --- Koha/Item.pm | 231 +++++++++++++++++++++++++++++++++++++++++++++++++ Koha/Patron.pm | 24 +++++ 2 files changed, 255 insertions(+) diff --git a/Koha/Item.pm b/Koha/Item.pm index d2b92c19568..b3126b20733 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -31,6 +31,7 @@ use C4::Reserves; use C4::ClassSource qw( GetClassSort ); use C4::Log qw( logaction ); +use Koha::AuthorisedValues; use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue; use Koha::Biblio::ItemGroups; use Koha::Checkouts; @@ -58,6 +59,7 @@ use Koha::StockRotationItem; use Koha::StockRotationRotas; use Koha::TrackedLinks; use Koha::Policy::Holds; +use Koha::DisplayItems; use base qw(Koha::Object); @@ -412,6 +414,13 @@ Returns the itemtype for the item based on whether item level itemtypes are set sub effective_itemtype { my ($self) = @_; + if ( C4::Context->preference('UseDisplayModule') ) { + if ( my $display = $self->active_display ) { + my $display_itype = $display->get_column('display_itype'); + return $display_itype if $display_itype; + } + } + return $self->_result()->effective_itemtype(); } @@ -778,6 +787,44 @@ sub check_booking { return $bookings_count ? 0 : 1; } +=head3 active_display_item + + my $display_item = $item->active_display_item; + +Returns the Koha::DisplayItem object if this item is part of an active display, undef otherwise. +An active display is one where enabled = 1 and the current date falls within the start_date and end_date range (if set). + +=cut + +sub active_display_item { + my ($self) = @_; + + return unless C4::Context->preference('UseDisplayModule'); + + my $dtf = Koha::Database->new->schema->storage->datetime_parser; + my $today = dt_from_string(); + + my $display_item = Koha::DisplayItems->search( + { + itemnumber => $self->itemnumber, + 'display.enabled' => 1, + -and => [ + -or => [ + { 'display.start_date' => undef }, + { 'display.start_date' => { '<=' => $dtf->format_date($today) } } + ], + -or => [ + { 'display.end_date' => undef }, + { 'display.end_date' => { '>=' => $dtf->format_date($today) } } + ] + ] + }, + { join => 'display' } + )->next; + + return $display_item; +} + =head3 request_transfer my $transfer = $item->request_transfer( @@ -1949,6 +1996,10 @@ sub to_api { $overrides->{effective_item_type_id} = $self->effective_itemtype; $overrides->{effective_not_for_loan_status} = $self->effective_not_for_loan_status; $overrides->{effective_bookable} = $self->effective_bookable; + $overrides->{effective_location} = $self->effective_location; + $overrides->{effective_collection_code} = $self->effective_collection_code; + $overrides->{effective_home_library_id} = $self->effective_homebranch; + $overrides->{effective_holding_library_id} = $self->effective_holdingbranch; return { %$response, %$overrides }; } @@ -2069,6 +2120,166 @@ sub effective_bookable { return $self->bookable // $self->itemtype->bookable; } +=head3 effective_location + + my $location = $item->effective_location; + +Returns the effective location of the item. If the item is on an active display +with a display_location, returns the display_location. Otherwise, returns +the item's location. + +=cut + +sub effective_location { + my ($self) = @_; + + return $self->location unless C4::Context->preference('UseDisplayModule'); + + if ( my $display = $self->active_display ) { + if ( $display->display_location ) { + return $display->display_location; + } + return "DISPLAY: " . $display->display_name; + } + + return $self->location; +} + +=head3 effective_collection_code + + my $ccode = $item->effective_collection_code; + +Returns the effective collection code for the item. If the item is part of an active display +with a display_code set, returns that code. Otherwise returns the item's regular ccode. + +=cut + +sub effective_collection_code { + my ($self) = @_; + + return $self->ccode unless C4::Context->preference('UseDisplayModule'); + + if ( my $display = $self->active_display ) { + my $display_code = $display->get_column('display_code'); + return $display_code if $display_code; + } + + return $self->ccode; +} + +=head3 effective_homebranch + + my $homebranch = $item->effective_homebranch; + +Returns the effective home branch for the item. If the item is part of an active display +with a display_branch set, returns that branch. Otherwise returns the item's regular homebranch. + +=cut + +sub effective_homebranch { + my ($self) = @_; + + return $self->get_column('homebranch') unless C4::Context->preference('UseDisplayModule'); + + if ( my $display = $self->active_display ) { + my $display_branch = $display->get_column('display_branch'); + return $display_branch if $display_branch; + } + + return $self->get_column('homebranch'); +} + +=head3 effective_holdingbranch + + my $holdingbranch = $item->effective_holdingbranch; + +Returns the effective holding branch for the item. If the item is part of an active display +with a display_holding_branch set, returns that branch. Otherwise returns the item's regular holdingbranch. + +=cut + +sub effective_holdingbranch { + my ($self) = @_; + + return $self->get_column('holdingbranch') unless C4::Context->preference('UseDisplayModule'); + + if ( my $display = $self->active_display ) { + my $display_holding_branch = $display->get_column('display_holding_branch'); + return $display_holding_branch if $display_holding_branch; + } + + return $self->get_column('holdingbranch'); +} + +=head3 active_display + + my $display = $item->active_display; + +Returns the active display for this item, if any. Returns undef if the item is not +currently in an active display. + +An active display is one that: +- Is enabled +- Has a start_date that is today or in the past (or no start_date) +- Has an end_date that is today or in the future (or no end_date) +- Has a date_remove on the display_item that is today or in the future (or no date_remove) + +=cut + +sub active_display { + my ($self) = @_; + + return unless C4::Context->preference('UseDisplayModule'); + + my $display_item_rs = $self->_result->display_items( + { + 'display.enabled' => 1, + '-or' => [ + 'display.start_date' => { '<=', \'CURDATE()' }, + 'display.start_date' => undef + ], + '-and' => [ + '-or' => [ + 'display.end_date' => { '>=', \'CURDATE()' }, + 'display.end_date' => undef + ], + '-or' => [ + 'date_remove' => { '>=', \'CURDATE()' }, + 'date_remove' => undef + ] + ] + }, + { + join => 'display', + order_by => { -desc => 'date_added' } + } + ); + + if ( my $display_item = $display_item_rs->first ) { + return $display_item->display; + } + + return; +} + +=head3 location_description + + my $description = $item->location_description(); + +Returns the human-readable description for the item's location from authorised values. + +=cut + +sub location_description { + my ($self) = @_; + + return '' unless $self->location; + + my $av = Koha::AuthorisedValues->get_description_by_koha_field( + { kohafield => 'items.location', authorised_value => $self->location } ); + return $av->{lib} || $self->location; +} + =head3 orders my $orders = $item->orders(); @@ -2759,6 +2970,26 @@ sub strings_map { } } + if ( my $effective_loc = $self->effective_location ) { + my $description; + + # Handle display locations that start with "DISPLAY:" + if ( $effective_loc =~ /^DISPLAY:/ ) { + $description = $effective_loc; + } else { + + # Look up authorized value for regular locations + my $av = Koha::AuthorisedValues->get_description_by_koha_field( + { kohafield => 'items.location', authorised_value => $effective_loc } ); + $description = $av->{lib} || $effective_loc; + } + $strings->{effective_location} = { + category => 'LOC', + str => $description, + type => 'av', + }; + } + return $strings; } diff --git a/Koha/Patron.pm b/Koha/Patron.pm index 03276ff6a54..0439d5ab33f 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -2277,6 +2277,30 @@ sub libraries_where_can_see_patrons { ); } +=head3 libraries_where_can_edit_displays + + my $libraries = $patron->libraries_where_can_edit_displays; + +Return the list of branchcodes(!) of libraries the patron is allowed to edit +displays for. The branchcodes are arbitrarily returned sorted. + +If the patron has the 'add_items_to_display_from_any_libraries' permission, +an empty list is returned as a signal they have access to all libraries. + +=cut + +sub libraries_where_can_edit_displays { + my ($self) = @_; + + return $self->libraries_where_can_see_things( + { + permission => 'displays', + subpermission => 'add_items_to_display_from_any_libraries', + group_feature => 'ft_display_group', + } + ); +} + =head3 can_see_things_from my $can_see = $patron->can_see_things_from( -- 2.50.1 (Apple Git-155)