Bugzilla – Attachment 193729 Details for
Bug 14962
Temp Shelving Location / On Display Module
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 14962: On Display code for Intranet scripts & templates
65aa5be.patch (text/plain), 176.90 KB, created by
Martin Renvoize (ashimema)
on 2026-02-24 13:35:41 UTC
(
hide
)
Description:
Bug 14962: On Display code for Intranet scripts & templates
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2026-02-24 13:35:41 UTC
Size:
176.90 KB
patch
obsolete
>From 65aa5be48e3c7b0f8a0cb78f09812dd9baaaf84f Mon Sep 17 00:00:00 2001 >From: Jake Deery <jake.deery@openfifth.co.uk> >Date: Mon, 1 Dec 2025 14:45:40 +0000 >Subject: [PATCH] Bug 14962: On Display code for Intranet scripts & templates > >This patch makes the necessary changes to the Intranet to make sure effective locations, collection codes, and branches are correctly displayed. >Please see the test files commit for instructions on how to test this bundle of patches. > >Sponsored-by: ByWater Solutions >Signed-of-by: Martin Renvoize <martin.renvoize@openfifth.co.uk> >--- > admin/library_groups.pl | 4 + > basket/basket.pl | 19 +- > catalogue/itemsearch.pl | 7 + > catalogue/moredetail.pl | 39 +- > catalogue/search.pl | 1 + > cataloguing/additem.pl | 15 + > circ/overdue.pl | 65 +-- > circ/pendingreserves.pl | 26 +- > circ/returns.pl | 2 + > circ/view_holdsqueue.pl | 28 +- > display/display-home.pl | 54 +++ > .../prog/css/src/staff-global.scss | 5 + > .../prog/en/includes/action-logs.inc | 10 + > .../prog/en/includes/cat-toolbar.inc | 70 +++ > .../catalogue/itemsearch_item.csv.inc | 2 +- > .../catalogue/itemsearch_item.json.inc | 11 +- > .../prog/en/includes/display-search.inc | 35 ++ > .../intranet-tmpl/prog/en/includes/header.inc | 3 + > .../tables/items/catalogue_detail.inc | 222 +++++++++- > .../prog/en/includes/permissions.inc | 24 + > .../prog/en/includes/waiting_holds.inc | 2 +- > .../prog/en/modules/admin/library_groups.tt | 24 +- > .../admin/preferences/circulation.pref | 7 + > .../en/modules/admin/preferences/logs.pref | 6 + > .../prog/en/modules/basket/basket.tt | 4 +- > .../prog/en/modules/catalogue/detail.tt | 413 ++++++++++++++++++ > .../prog/en/modules/catalogue/moredetail.tt | 17 +- > .../prog/en/modules/catalogue/results.tt | 10 + > .../prog/en/modules/cataloguing/additem.tt | 267 ++++++----- > .../prog/en/modules/circ/article-requests.tt | 12 +- > .../prog/en/modules/circ/branchtransfers.tt | 2 +- > .../prog/en/modules/circ/on-site_checkouts.tt | 2 +- > .../prog/en/modules/circ/overdue.tt | 2 +- > .../prog/en/modules/circ/pendingbookings.tt | 10 +- > .../prog/en/modules/circ/pendingreserves.tt | 22 +- > .../prog/en/modules/circ/returns.tt | 9 +- > .../prog/en/modules/circ/view_holdsqueue.tt | 34 +- > .../prog/en/modules/display/display-home.tt | 36 ++ > .../prog/en/modules/intranet-main.tt | 6 + > .../en/modules/recalls/recalls_to_pull.tt | 4 +- > .../prog/en/modules/reports/itemslost.tt | 2 +- > .../prog/en/modules/tags/list.tt | 2 +- > .../prog/en/modules/tools/viewlog.tt | 2 +- > .../prog/en/modules/virtualshelves/shelves.tt | 4 +- > .../prog/js/fetch/display-api-client.js | 6 +- > .../prog/js/fetch/item-api-client.js | 11 +- > .../Display/DisplaysBatchAddItems.vue | 47 +- > .../Display/DisplaysBatchRemoveItems.vue | 38 +- > .../components/Display/DisplaysResource.vue | 174 ++++---- > .../prog/js/vue/components/Display/Main.vue | 26 +- > .../prog/js/vue/fetch/api-client.js | 4 +- > .../prog/js/vue/routes/display.js | 8 +- > recalls/recalls_to_pull.pl | 2 +- > reserve/request.pl | 5 + > 54 files changed, 1492 insertions(+), 370 deletions(-) > create mode 100755 display/display-home.pl > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/display-search.inc > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/display/display-home.tt > >diff --git a/admin/library_groups.pl b/admin/library_groups.pl >index 5cf759928d9..0f5c50f6255 100755 >--- a/admin/library_groups.pl >+++ b/admin/library_groups.pl >@@ -52,6 +52,7 @@ if ( $op eq 'cud-add' ) { > my $ft_search_groups_staff = $cgi->param('ft_search_groups_staff') || 0; > my $ft_local_hold_group = $cgi->param('ft_local_hold_group') || 0; > my $ft_local_float_group = $cgi->param('ft_local_float_group') || 0; >+ my $ft_display_group = $cgi->param('ft_display_group') || 0; > > if ( !$branchcode && Koha::Library::Groups->search( { title => $title } )->count() ) { > $template->param( error_duplicate_title => $title ); >@@ -68,6 +69,7 @@ if ( $op eq 'cud-add' ) { > ft_local_hold_group => $ft_local_hold_group, > ft_limit_item_editing => $ft_limit_item_editing, > ft_local_float_group => $ft_local_float_group, >+ ft_display_group => $ft_display_group, > branchcode => $branchcode, > } > )->store(); >@@ -88,6 +90,7 @@ if ( $op eq 'cud-add' ) { > my $ft_search_groups_staff = $cgi->param('ft_search_groups_staff') || 0; > my $ft_local_hold_group = $cgi->param('ft_local_hold_group') || 0; > my $ft_local_float_group = $cgi->param('ft_local_float_group') || 0; >+ my $ft_display_group = $cgi->param('ft_display_group') || 0; > > if ($id) { > my $group = Koha::Library::Groups->find($id); >@@ -102,6 +105,7 @@ if ( $op eq 'cud-add' ) { > ft_search_groups_staff => $ft_search_groups_staff, > ft_local_hold_group => $ft_local_hold_group, > ft_local_float_group => $ft_local_float_group, >+ ft_display_group => $ft_display_group, > } > )->store(); > >diff --git a/basket/basket.pl b/basket/basket.pl >index 49d98371f4c..1ff5c4d7937 100755 >--- a/basket/basket.pl >+++ b/basket/basket.pl >@@ -17,6 +17,7 @@ > > use Modern::Perl; > use CGI qw ( -utf8 ); >+use C4::Context; > use C4::Koha; > use C4::Biblio qw( > GetMarcSeries >@@ -29,6 +30,7 @@ use C4::Output qw( output_html_with_http_headers ); > use Koha::AuthorisedValues; > use Koha::Biblios; > use Koha::CsvProfiles; >+use Koha::Items; > > my $query = CGI->new; > >@@ -87,7 +89,15 @@ foreach my $biblionumber (@bibs) { > > $num++; > $dat->{biblionumber} = $biblionumber; >- $dat->{ITEM_RESULTS} = $biblio->items->search_ordered; >+ my $items = $biblio->items->search_ordered; >+ >+ # Add effective_location for display module support >+ if ( C4::Context->preference('UseDisplayModule') ) { >+ foreach my $item ( $items->as_list ) { >+ $item->{effective_location} = $item->effective_location; >+ } >+ } >+ $dat->{ITEM_RESULTS} = $items; > $dat->{MARCNOTES} = $marcnotesarray; > $dat->{MARCSUBJCTS} = $marcsubjctsarray; > $dat->{MARCAUTHORS} = $marcauthorsarray; >@@ -107,9 +117,10 @@ my $resultsarray = \@results; > # my $itemsarray=\@items; > > $template->param( >- BIBLIO_RESULTS => $resultsarray, >- csv_profiles => Koha::CsvProfiles->search( { type => 'marc', used_for => 'export_records' } ), >- bib_list => $bib_list, >+ BIBLIO_RESULTS => $resultsarray, >+ csv_profiles => Koha::CsvProfiles->search( { type => 'marc', used_for => 'export_records' } ), >+ bib_list => $bib_list, >+ UseDisplayModule => C4::Context->preference('UseDisplayModule'), > ); > > output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/catalogue/itemsearch.pl b/catalogue/itemsearch.pl >index ae8dd8241d6..6ac30c47d71 100755 >--- a/catalogue/itemsearch.pl >+++ b/catalogue/itemsearch.pl >@@ -30,6 +30,7 @@ use C4::Koha qw( GetAuthorisedValues ); > use Koha::AuthorisedValues; > use Koha::Biblios; > use Koha::Item::Search::Field qw(GetItemSearchFields); >+use Koha::Items; > use Koha::ItemTypes; > use Koha::Libraries; > >@@ -292,6 +293,12 @@ if ( defined $format and $format ne 'shareable' ) { > $item->{biblioitem} = $biblio->biblioitem->unblessed; > my $checkout = Koha::Checkouts->find( { itemnumber => $item->{itemnumber} } ); > $item->{checkout} = $checkout; >+ >+ # Add effective_location for display module support >+ if ( C4::Context->preference('UseDisplayModule') ) { >+ my $item_obj = Koha::Items->find( $item->{itemnumber} ); >+ $item->{effective_location} = $item_obj ? $item_obj->effective_location : $item->{location}; >+ } > } > } > >diff --git a/catalogue/moredetail.pl b/catalogue/moredetail.pl >index cdd6c09be08..3806f6c0d30 100755 >--- a/catalogue/moredetail.pl >+++ b/catalogue/moredetail.pl >@@ -158,10 +158,10 @@ foreach my $item (@items) { > > my $item_info = $item->unblessed; > $item_info->{object} = $item; >- $item_info->{itype} = $itemtypes->{ $item->itype }->{'translated_description'} >- if exists $itemtypes->{ $item->itype }; >- $item_info->{effective_itemtype} = $itemtypes->{ $item->effective_itemtype }; >- $item_info->{'ccode'} = $ccodes->{ $item->ccode } if $ccodes && $item->ccode && exists $ccodes->{ $item->ccode }; >+ $item_info->{itype} = $itemtypes->{ $item->effective_itemtype }->{'translated_description'} >+ if exists $itemtypes->{ $item->effective_itemtype }; >+ $item_info->{'ccode'} = $ccodes->{ $item->effective_collection_code } >+ if $ccodes && $item->effective_collection_code && exists $ccodes->{ $item->effective_collection_code }; > if ( defined $item->copynumber ) { > $item_info->{'displaycopy'} = 1; > if ( defined $copynumbers->{ $item_info->{'copynumber'} } ) { >@@ -256,6 +256,37 @@ foreach my $item (@items) { > > $item_info->{nomod} = !$patron->can_edit_items_from( $item->homebranch ); > >+ if ( C4::Context->preference('UseDisplayModule') ) { >+ my @displays; >+ my @display_items = Koha::DisplayItems->search( >+ { itemnumber => $item->itemnumber }, >+ { >+ order_by => { '-desc' => 'date_added' }, >+ } >+ )->as_list; >+ >+ foreach my $display_item (@display_items) { >+ push @displays, $display_item->display; >+ } >+ >+ $item_info->{display_items} = \@display_items if @display_items; >+ $item_info->{displays} = \@displays if @displays; >+ } >+ >+ if ( C4::Context->preference('UseDisplayModule') && $item->effective_homebranch ) { >+ my $effective_homebranch = $item->effective_homebranch; >+ my $effective_homebranch_id = $item->effective_homebranch->branchcode; >+ >+ $item_info->{homebranch} = $effective_homebranch_id; >+ } >+ >+ if ( C4::Context->preference('UseDisplayModule') && $item->effective_holdingbranch ) { >+ my $effective_holdingbranch = $item->effective_holdingbranch; >+ my $effective_holdingbranch_id = $item->effective_holdingbranch->branchcode; >+ >+ $item_info->{holdingbranch} = $effective_holdingbranch_id; >+ } >+ > push @item_data, $item_info; > } > >diff --git a/catalogue/search.pl b/catalogue/search.pl >index 957a9f9dcfc..aa38fc5824a 100755 >--- a/catalogue/search.pl >+++ b/catalogue/search.pl >@@ -708,6 +708,7 @@ if ($hits) { > sort_by => \@sort_by > } > ); >+ > $template->param( hits_to_paginate => $hits_to_paginate ); > $template->param( SEARCH_RESULTS => \@newresults ); > >diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl >index 5c3e2005124..784be908f7b 100755 >--- a/cataloguing/additem.pl >+++ b/cataloguing/additem.pl >@@ -165,6 +165,11 @@ if ( $op eq 'edititem' || $op eq 'dupeitem' ) { > if ( !$item ) { > $template->param( biblio => $biblio, item_doesnt_exist => 1 ); > output_and_exit( $input, $cookie, $template, 'unknown_item' ); >+ } else { >+ my $ondisplay = $item->active_display ? 1 : undef; >+ my $nomod = $ondisplay; >+ >+ $template->param( ondisplay => $ondisplay, nomod => $nomod ); > } > } > >@@ -698,6 +703,16 @@ my @items; > for my $item ( $biblio->items->as_list, $biblio->host_items->as_list ) { > my $i = $item->columns_to_str; > $i->{nomod} = 1 unless $patron->can_edit_items_from( $item->homebranch ); >+ >+ if ( C4::Context->preference('UseDisplayModule') ) { >+ if ( $item->active_display ) { >+ $i->{active_display_id} = $item->active_display->display_id; >+ $i->{active_display_name} = $item->active_display->display_name; >+ $i->{ondisplay} = 1; >+ $i->{nomod} = 1; >+ } >+ } >+ > push @items, $i; > } > >diff --git a/circ/overdue.pl b/circ/overdue.pl >index 2d58dd27ee4..9d91eb9ab45 100755 >--- a/circ/overdue.pl >+++ b/circ/overdue.pl >@@ -28,6 +28,7 @@ use Koha::DateUtils qw( dt_from_string ); > use Koha::Patron::Attribute::Types; > use DateTime; > use DateTime::Format::MySQL; >+use Koha::Items; > > my $input = CGI->new; > my $showall = $input->param('showall'); >@@ -349,36 +350,40 @@ if ($noreport) { > } > > push @overduedata, { >- patron => Koha::Patrons->find( $data->{borrowernumber} ), >- duedate => $data->{date_due}, >- borrowernumber => $data->{borrowernumber}, >- cardnumber => $data->{cardnumber}, >- borrowertitle => $data->{borrowertitle}, >- surname => $data->{surname}, >- firstname => $data->{firstname}, >- streetnumber => $data->{streetnumber}, >- streettype => $data->{streettype}, >- address => $data->{address}, >- address2 => $data->{address2}, >- city => $data->{city}, >- zipcode => $data->{zipcode}, >- country => $data->{country}, >- phone => $data->{phone}, >- email => $data->{email}, >- branchcode => $data->{branchcode}, >- barcode => $data->{barcode}, >- datelastborrowed => $data->{datelastborrowed}, >- itemnum => $data->{itemnumber}, >- issuedate => $data->{issuedate}, >- biblionumber => $data->{biblionumber}, >- title => $data->{title}, >- subtitle => $data->{subtitle}, >- part_number => $data->{part_number}, >- part_name => $data->{part_name}, >- author => $data->{author}, >- homebranchcode => $data->{homebranch}, >- holdingbranchcode => $data->{holdingbranch}, >- location => $data->{location}, >+ patron => Koha::Patrons->find( $data->{borrowernumber} ), >+ duedate => $data->{date_due}, >+ borrowernumber => $data->{borrowernumber}, >+ cardnumber => $data->{cardnumber}, >+ borrowertitle => $data->{borrowertitle}, >+ surname => $data->{surname}, >+ firstname => $data->{firstname}, >+ streetnumber => $data->{streetnumber}, >+ streettype => $data->{streettype}, >+ address => $data->{address}, >+ address2 => $data->{address2}, >+ city => $data->{city}, >+ zipcode => $data->{zipcode}, >+ country => $data->{country}, >+ phone => $data->{phone}, >+ email => $data->{email}, >+ branchcode => $data->{branchcode}, >+ barcode => $data->{barcode}, >+ datelastborrowed => $data->{datelastborrowed}, >+ itemnum => $data->{itemnumber}, >+ issuedate => $data->{issuedate}, >+ biblionumber => $data->{biblionumber}, >+ title => $data->{title}, >+ subtitle => $data->{subtitle}, >+ part_number => $data->{part_number}, >+ part_name => $data->{part_name}, >+ author => $data->{author}, >+ homebranchcode => $data->{homebranch}, >+ holdingbranchcode => $data->{holdingbranch}, >+ location => $data->{location}, >+ effective_location => do { >+ my $item = Koha::Items->find( $data->{itemnumber} ); >+ $item ? $item->effective_location : ''; >+ }, > itemcallnumber => $data->{itemcallnumber}, > replacementprice => $data->{replacementprice}, > itemnotes_nonpublic => $data->{itemnotes_nonpublic}, >diff --git a/circ/pendingreserves.pl b/circ/pendingreserves.pl >index 140b7b0bd11..1457dec5a60 100755 >--- a/circ/pendingreserves.pl >+++ b/circ/pendingreserves.pl >@@ -260,7 +260,7 @@ foreach my $bibnum (@biblionumbers) { > # get available item types for each biblio > my @res_itemtypes; > if ( C4::Context->preference('item-level_itypes') ) { >- @res_itemtypes = uniq map { defined $_->itype ? $_->itype : () } @$items; >+ @res_itemtypes = uniq map { defined $_->effective_itemtype ? $_->effective_itemtype : () } @$items; > } else { > @res_itemtypes = Koha::Biblioitems->search( > { biblionumber => $bibnum, itemtype => { '!=', undef } }, >@@ -270,19 +270,20 @@ foreach my $bibnum (@biblionumbers) { > } > )->get_column('itemtype'); > } >+ > $hold_info->{itemtypes} = \@res_itemtypes; > > my $res_info = $all_holds->{$bibnum}; > > # get available values for each biblio > my $fields = { >- collections => 'ccode', >- locations => 'location', >+ collections => 'effective_collection_code', >+ locations => 'effective_location', > callnumbers => 'itemcallnumber', > enumchrons => 'enumchron', > copynumbers => 'copynumber', > barcodes => 'barcode', >- holdingbranches => 'holdingbranch' >+ holdingbranches => 'effective_holdingbranch_id' > }; > > while ( my ( $key, $field ) = each %$fields ) { >@@ -316,6 +317,23 @@ foreach my $bibnum (@biblionumbers) { > $hold_info->{hold} = $res_info; > $hold_info->{item_group} = $res_info->item_group; > >+ if ( C4::Context->preference('UseDisplayModule') ) { >+ my @displays; >+ my @display_items = Koha::DisplayItems->search( >+ { itemnumber => $hold_info->{item}->itemnumber }, >+ { >+ order_by => { '-desc' => 'date_added' }, >+ } >+ )->as_list; >+ >+ foreach my $display_item (@display_items) { >+ push @displays, $display_item->display; >+ } >+ >+ $hold_info->{display_items} = \@display_items if @display_items; >+ $hold_info->{displays} = \@displays if @displays; >+ } >+ > push @holds_info, $hold_info; > } > >diff --git a/circ/returns.pl b/circ/returns.pl >index 97b23534900..24206f53a48 100755 >--- a/circ/returns.pl >+++ b/circ/returns.pl >@@ -759,6 +759,8 @@ foreach my $code ( keys %$messages ) { > ; > } elsif ( $code eq 'InBundle' ) { > $template->param( InBundle => $messages->{InBundle} ); >+ } elsif ( $code eq 'RemovedFromDisplay' ) { >+ $template->param( RemovedFromDisplay => $messages->{RemovedFromDisplay} ); > } elsif ( $code eq 'UpdateLastSeenError' ) { > $err{UpdateLastSeenError} = $messages->{UpdateLastSeenError}; > } else { >diff --git a/circ/view_holdsqueue.pl b/circ/view_holdsqueue.pl >index 460c5d6ba90..ef2d6c9e09f 100755 >--- a/circ/view_holdsqueue.pl >+++ b/circ/view_holdsqueue.pl >@@ -27,6 +27,7 @@ use C4::Auth qw( get_template_and_user ); > use C4::Output qw( output_html_with_http_headers ); > use C4::HoldsQueue qw( GetHoldsQueueItems ); > use Koha::BiblioFrameworks; >+use Koha::Items; > use Koha::ItemTypes; > > my $query = CGI->new; >@@ -59,13 +60,38 @@ if ($run_report) { > } > ); > >+ my @itemsloop; >+ foreach my $item ( $items->as_list ) { >+ my $itemsloo = $item->unblessed; >+ $itemsloo->{object} = $item; >+ >+ if ( C4::Context->preference('UseDisplayModule') ) { >+ my @displays; >+ my @display_items = Koha::DisplayItems->search( >+ { itemnumber => $item->itemnumber }, >+ { >+ order_by => { '-desc' => 'date_added' }, >+ } >+ )->as_list; >+ >+ foreach my $display_item (@display_items) { >+ push @displays, $display_item->display; >+ } >+ >+ $itemsloo->{display_items} = \@display_items if @display_items; >+ $itemsloo->{displays} = \@displays if @displays; >+ } >+ >+ push @itemsloop, $itemsloo; >+ } >+ > $template->param( > branchlimit => $branchlimit, > itemtypeslimit => $itemtypeslimit, > ccodeslimit => $ccodeslimit, > locationslimit => $locationslimit, > total => $items->count, >- itemsloop => $items, >+ itemsloop => \@itemsloop, > run_report => $run_report, > ); > } >diff --git a/display/display-home.pl b/display/display-home.pl >new file mode 100755 >index 00000000000..798e7f5ec7c >--- /dev/null >+++ b/display/display-home.pl >@@ -0,0 +1,54 @@ >+#!/usr/bin/perl >+ >+# Copyright 2025-2026 Open Fifth Ltd >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <https://www.gnu.org/licenses>. >+ >+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 Koha::Database::Columns; >+ >+my $query = CGI->new; >+my ( $template, $loggedinuser, $cookie, $userflags ) = get_template_and_user( >+ { >+ template_name => 'display/display-home.tt', >+ query => $query, >+ type => 'intranet', >+ flagsrequired => { displays => '*' }, >+ } >+); >+ >+my $columns = Koha::Database::Columns::columns; >+$template->param( >+ db_columns => { >+ map { >+ my $table = $_; >+ map { ( $table . '.' . $_ => $columns->{$table}->{$_} ) } >+ keys %{ $columns->{$table} } >+ } qw( biblio biblioitems items ) >+ }, >+ api_mappings => { >+ items => Koha::Item->to_api_mapping, >+ biblioitems => Koha::Biblioitem->to_api_mapping, >+ biblio => Koha::Biblio->to_api_mapping, >+ }, >+); >+ >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss >index 23c42d00425..d52c8a484bc 100644 >--- a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss >+++ b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss >@@ -2028,6 +2028,11 @@ i { > font-style: italic; > } > >+// style for displays in catalogsearch >+.displays { >+ display: block; >+} >+ > #closewindow { > margin-top: 2em; > text-align: center; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc >index 867173a69c7..cb2f44cbe3f 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc >@@ -24,6 +24,8 @@ > <span>Circulation</span>[% UNLESS Koha.Preference('IssueLog') %]<i class="log-disabled fa-solid fa-triangle-exclamation" title="Log not enabled" data-log="IssueLog"></i>[% END %] > [% CASE 'CLAIMS' %] > <span>Claims</span>[% UNLESS Koha.Preference('ClaimsLog') %]<i class="log-disabled fa-solid fa-triangle-exclamation" title="Log not enabled" data-log="ClaimsLog"></i>[% END %] >+ [% CASE 'DISPLAYS' %] >+ <span>Displays</span>[% UNLESS Koha.Preference('DisplayItemsLog') %]<i class="log-disabled fa-solid fa-triangle-exclamation" title="Log not enabled" data-log="DisplayItemsLog"></i>[% END %] > [% CASE 'FINES' %] > <span>Fines</span>[% UNLESS Koha.Preference('FinesLog') %]<i class="log-disabled fa-solid fa-triangle-exclamation" title="Log not enabled" data-log="FinesLog"></i>[% END %] > [% CASE 'SYSTEMPREFERENCE' %] >@@ -159,6 +161,14 @@ > <span>Modify cardnumber</span> > [% CASE 'RESET 2FA' %] > <span>Reset 2FA</span> >+ [% CASE 'ENABLE' %] >+ <span>Enable</span> >+ [% CASE 'DISABLE' %] >+ <span>Disable</span> >+ [% CASE 'ADD_ITEM' %] >+ <span>Add item</span> >+ [% CASE 'REMOVE_ITEM' %] >+ <span>Remove item</span> > [% CASE %] > [% action | html %] > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc >index 68b4c24e45c..18476132ae2 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cat-toolbar.inc >@@ -308,11 +308,81 @@ > [% END %] > [% END %] > >+ [% IF Koha.Preference('UseDisplayModule') && CAN_user_displays %] >+ <div class="btn-group"> >+ <button type="button" class="btn btn-default dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"><i class="fa fa-tv"></i> Add to display</button> >+ <ul class="dropdown-menu" id="display-dropdown"> >+ <li class="text-center"><i class="fa fa-spinner fa-spin"></i> Loading displays...</li> >+ </ul> >+ </div> >+ [% END %] >+ > [% FOREACH p IN plugins %] > [% p.intranet_catalog_biblio_enhancements_toolbar_button | $raw %] > [% END %] > </div> > >+<!-- Modal for Add to Display --> >+[% IF Koha.Preference('UseDisplayModule') && CAN_user_displays %] >+ <div class="modal fade" id="addToDisplayModal" tabindex="-1" role="dialog" aria-labelledby="addToDisplayModalLabel" aria-hidden="true"> >+ <div class="modal-dialog modal-lg"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h4 class="modal-title" id="addToDisplayModalLabel">Add items to display</h4> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <form id="addToDisplayForm"> >+ <div class="modal-body"> >+ <div class="row"> >+ <div class="col-md-6"> >+ <label for="display-select" class="form-label">Select display:</label> >+ <select id="display-select" class="form-select" required> >+ <option value="">Loading displays...</option> >+ </select> >+ </div> >+ <div class="col-md-6"> >+ <label for="date-remove" class="form-label">Remove date (optional):</label> >+ <div class="input-group"> >+ <input type="date" id="date-remove" class="form-control" /> >+ <button class="btn btn-outline-secondary" type="button" id="clear-date" title="Clear date"> >+ <i class="fa fa-times"></i> >+ </button> >+ </div> >+ </div> >+ </div> >+ <div class="row mt-3"> >+ <div class="col-12"> >+ <label class="form-label">Select items to add:</label> >+ <div class="table-responsive"> >+ <table id="display-items-table" class="table table-striped"> >+ <thead> >+ <tr> >+ <th><input type="checkbox" id="select-all-display-items" /></th> >+ <th>Barcode</th> >+ <th>Current library</th> >+ <th>Home library</th> >+ <th>Location</th> >+ <th>Collection</th> >+ <th>Call number</th> >+ <th>Status</th> >+ </tr> >+ </thead> >+ <tbody> </tbody> >+ </table> >+ </div> >+ </div> >+ </div> >+ </div> >+ <div class="modal-footer"> >+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> >+ <button type="submit" class="btn btn-primary" id="add-to-display-btn">Add to display</button> >+ </div> >+ </form> >+ </div> >+ </div> >+ </div> >+[% END %] >+ > <!--Modal for Dublin Core--> > <div class="modal" id="exportModal_" tabindex="-1" role="dialog" aria-labelledby="exportLabelexportModal_" aria-hidden="true"> > <div class="modal-dialog"> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc >index 9dd823445ee..be021dd5e30 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc >@@ -8,4 +8,4 @@ > [%- SET biblioitem = item.biblioitem -%] > [%- SET delimiter = Koha.CSVDelimiter() -%] > "[% biblio.title | replace('"', '""') | $raw %] >-[% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %]by[% END %][% biblio.author | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% (biblioitem.publicationyear || biblio.copyrightdate) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% biblioitem.publishercode | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => item.ccode ) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.barcode | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.itemnumber | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.enumchron | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.itemcallnumber | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% Branches.GetName(item.homebranch) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% Branches.GetName(item.holdingbranch) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField(frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => item.location) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% ItemTypes.GetDescription(item.itype) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.stocknumber | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField(frameworkcode => biblio.frameworkcode, kohafield => 'items.notforloan', authorised_value => item.notforloan) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.itemlost', authorised_value => item.itemlost ) || "" | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.withdrawn', authorised_value => item.withdrawn ) || "" | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.damaged', authorised_value => item.damaged ) || "" | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.dateaccessioned | $KohaDates | $raw %]"[%- delimiter | $raw -%]"[% (item.issues || 0) | $raw %]"[%- delimiter | $raw -%]"[% item.datelastborrowed | $KohaDates | $raw %]"[%- delimiter | $raw -%]"[% IF item.checkout %][% item.checkout.date_due | $KohaDates | $raw %][% END %]" >+[% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %]by[% END %][% biblio.author | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% (biblioitem.publicationyear || biblio.copyrightdate) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% biblioitem.publishercode | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => item.effective_collection_code ) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.barcode | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.itemnumber | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.enumchron | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.itemcallnumber | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% Branches.GetName(item.effective_homebranch) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% Branches.GetName(item.effective_holdingbranch) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField(frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => item.effective_location) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% ItemTypes.GetDescription(item.effective_itemtype) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.stocknumber | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField(frameworkcode => biblio.frameworkcode, kohafield => 'items.notforloan', authorised_value => item.notforloan) | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.itemlost', authorised_value => item.itemlost ) || "" | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.withdrawn', authorised_value => item.withdrawn ) || "" | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.damaged', authorised_value => item.damaged ) || "" | replace('"', '""') | $raw %]"[%- delimiter | $raw -%]"[% item.dateaccessioned | $KohaDates | $raw %]"[%- delimiter | $raw -%]"[% (item.issues || 0) | $raw %]"[%- delimiter | $raw -%]"[% item.datelastborrowed | $KohaDates | $raw %]"[%- delimiter | $raw -%]"[% IF item.checkout %][% item.checkout.date_due | $KohaDates | $raw %][% END %]" >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc >index 2367c59f1b2..ec69e8f0149 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc >@@ -20,7 +20,16 @@ > <a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% biblio.biblionumber | uri %]#item[% item.itemnumber | uri %]" title="Go to item details">[% item.barcode | html | $To %]</a> > [%~ END %]", > "[% item.itemnumber | html %]", "[% item.enumchron | html | $To %]", "[% item.itemcallnumber | html | $To %]", "[% Branches.GetName(item.homebranch) | html %]", "[% Branches.GetName(item.holdingbranch) | html %]", >-"[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => item.location) | html %]", "[% ItemTypes.GetDescription(item.itype) | html %]", >+[% IF Koha.Preference('UseDisplayModule') && item.effective_location %] >+ [% SET effective_loc = item.effective_location %] >+ [% IF effective_loc.match('^DISPLAY:') %] >+ "[% effective_loc | html %]", "[% ItemTypes.GetDescription(item.itype) | html %]", >+ [% ELSE %] >+ "[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => effective_loc) | html %]", "[% ItemTypes.GetDescription(item.itype) | html %]", >+ [% END %] >+[% ELSE %] >+ "[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => item.location) | html %]", "[% ItemTypes.GetDescription(item.itype) | html %]", >+[% END %] > "[% item.stocknumber | html | $To %]", "[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.notforloan', authorised_value => item.notforloan) | html %]", > "[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.itemlost', authorised_value => item.itemlost ) || "" | html %]", > "[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.withdrawn', authorised_value => item.withdrawn ) || "" | html %]", >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/display-search.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/display-search.inc >new file mode 100644 >index 00000000000..dfd9014b355 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/display-search.inc >@@ -0,0 +1,35 @@ >+[% USE raw %] >+[% USE Koha %] >+[% PROCESS 'html_helpers.inc' %] >+<!-- display-search.inc --> >+[% WRAPPER tabs id="header_search" %] >+ [% WRAPPER tab_panels %] >+ [% IF ( CAN_user_circulate_circulate_remaining_permissions ) %] >+ [% INCLUDE 'patron-search-box.inc' bs_tab_active= 1 %] >+ [% INCLUDE 'checkin-search-box.inc' %] >+ [% INCLUDE 'renew-search-box.inc' %] >+ [% END %] >+ [% IF ( CAN_user_catalogue ) %] >+ [% INCLUDE 'catalogue-search-box.inc' %] >+ [% END %] >+ [% END # /tab_panels %] >+ [% WRAPPER tabs_nav %] >+ [% IF ( CAN_user_circulate_circulate_remaining_permissions ) %] >+ [% WRAPPER tab_item tabname="circ_search" bt_active= 1 %] >+ <i class="fa fa-fw fa-upload" aria-hidden="true"></i> <span class="tab-title">Check out</span> >+ [% END %] >+ [% WRAPPER tab_item tabname= "checkin_search" %] >+ <i class="fa fa-fw fa-download" aria-hidden="true"></i> <span class="tab-title">Check in</span> >+ [% END %] >+ [% WRAPPER tab_item tabname= "renew_search" %] >+ <i class="fa fa-fw fa-retweet" aria-hidden="true"></i> <span class="tab-title">Renew</span> >+ [% END %] >+ [% END %] >+ [% IF ( CAN_user_catalogue ) %] >+ [% WRAPPER tab_item tabname= "catalog_search" %] >+ <i class="fa fa-fw fa-search" aria-hidden="true"></i> <span class="tab-title">Search catalog</span> >+ [% END %] >+ [% END %] >+ [% END # /tabs_nav %] >+[% END # /WRAPPER tabs %] >+<!-- /display-search.inc --> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/header.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/header.inc >index 5b00a098c0d..bfa6e3df5c9 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/header.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/header.inc >@@ -70,6 +70,9 @@ > [% IF Koha.Preference('PreservationModule') && CAN_user_preservation %] > <li><a class="dropdown-item" href="/cgi-bin/koha/preservation/home.pl">Preservation</a></li> > [% END %] >+ [% IF Koha.Preference('UseDisplayModule') && CAN_user_displays %] >+ <li><a class="dropdown-item" href="/cgi-bin/koha/display/display-home.pl">Displays</a></li> >+ [% END %] > [% IF ( CAN_user_reports ) %] > <li><a class="dropdown-item" href="/cgi-bin/koha/reports/reports-home.pl">Reports</a></li> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc >index 9a1a3eaf65c..53dd6d781cc 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc >@@ -25,6 +25,7 @@ > <th id="[% tab | html %]_itemcallnumber" data-colname="itemcallnumber">Call number</th> > <th id="[% tab | html %]_enumchron" data-colname="enumchron">Serial enumeration / chronology</th> > <th id="[% tab | html %]_status" data-colname="status">Status</th> >+ <th id="[% tab | html %]_displays" data-colname="displays">Displays</th> > <th id="[% tab | html %]_lastseen" data-colname="lastseen">Last seen</th> > <th id="[% tab | html %]_issues" data-colname="issues">Checkouts</th> > <th id="[% tab | html %]_renewals" data-colname="renewals">Renewals</th> >@@ -175,7 +176,6 @@ > $("input[name='itemnumber'][type='checkbox']", tab).prop('checked', false); > itemSelectionBuildActionLinks(tab_id); > }); >- > }); > > let filters_shown = false; >@@ -256,7 +256,7 @@ > [%# In case or SeparateHoldings we may need to display the number of biblios in each tab %] > [%# Do we need separate/new endpoints or do we hack the somewhere client-side? %] > let item_table_url = "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?"; >- let embed = ["+strings,_status,home_library,holding_library,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,first_hold.desk"]; >+ let embed = ["+strings,_status,effective_home_library,effective_holding_library,home_library,holding_library,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,first_hold.desk"]; > [% IF Koha.Preference('LocalCoverImages') %] > embed.push('cover_image_ids'); > [% END %] >@@ -332,6 +332,21 @@ > return $("#" + tab_id + "_status select").val(); > }; > >+ [% IF Koha.Preference('UseDisplayModule') %] >+ const displaysFetch = $.ajax({ >+ url: '/api/v1/displays', >+ async: false, >+ method: 'GET', >+ headers: { 'x-koha-embed': 'display_items' }, >+ error: error => { >+ console.error(error); >+ }, >+ }); >+ const displays = displaysFetch.responseJSON || []; >+ [% ELSE %] >+ const displays = []; >+ [% END %] >+ > var items_table = $("#" + tab_id + '_table').kohaTable({ > ajax: { url: item_table_url }, > order: [], >@@ -382,14 +397,30 @@ > [% END %] > [% IF ( item_level_itypes ) %] > { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_item_type_id", // FIXME Cannot filter by biblioitem.itemtype >+ searchable: false, >+ orderable: false, >+ [% ELSE %] > data: "me.item_type_id", // FIXME Cannot filter by biblioitem.itemtype > datatype: "coded_value:item_type", > dataFilter: "item_types", > className: "itype", > searchable: true, > orderable: true, >+ [% END %] > render: function (data, type, row, meta) { > let node = ''; >+ [% IF Koha.Preference('UseDisplayModule') %] >+ let effective_item_type_description = row._strings.effective_item_type_id ? row._strings.effective_item_type_id.str : row.effective_item_type_id; >+ [% UNLESS noItemTypeImages %] >+ let image_location = item_type_image_locations[row.effective_item_type_id]; >+ node += image_location >+ ? '<img class="itemtype-image" src="%s" alt="" /> '.format(escape_str(image_location), escape_str(effective_item_type_description), escape_str(effective_item_type_description)) >+ : ''; >+ [% END %] >+ node += '<span class="itypedesc itypetext">%s</span>'.format(escape_str(effective_item_type_description)); >+ [% ELSE %] > let item_type_description = row._strings.item_type_id ? row._strings.item_type_id.str : row.item_type_id; > [% UNLESS noItemTypeImages %] > let image_location = item_type_image_locations[row.item_type_id]; >@@ -398,60 +429,132 @@ > : ''; > [% END %] > node += '<span class="itypedesc itypetext">%s</span>'.format(escape_str(item_type_description)); >+ [% END %] >+ > return node; > } > }, > [% END %] > { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_holding_library_id", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] > data: "holding_library.name:me.holding_library_id", > datatype: "coded_value:library", >- dataFilter: "libraries", >- className: "location", > searchable: true, > orderable: true, >+ dataFilter: "libraries", >+ className: "location", >+ [% END %] > render: function (data, type, row, meta) { >- return escape_str(row._strings.holding_library_id ? row._strings.holding_library_id.str : row.holding_library_id); >+ let nodes = ""; >+ let effective_holding_library_id_str = row._strings.effective_holding_library_id ? row._strings.effective_holding_library_id.str : row.effective_holding_library_id; >+ let holding_library_id_str = row._strings.holding_library_id ? row._strings.holding_library_id.str : row.holding_library_id; >+ >+ [% IF Koha.Preference('UseDisplayModule') %] >+ if (holding_library_id_str != effective_holding_library_id_str) { >+ nodes += '<a href="javascript:void(0)" onClick="handlePermanentLocation(this)" data-header="' + _("Permanent holding branch") + '" data-body="' + holding_library_id_str + '">'; >+ nodes += ' <i class="fa fa-info-circle" aria-hidden="true"></i>'; >+ nodes += '</a> '; >+ } >+ [% END %] >+ >+ nodes += escape_str(effective_holding_library_id_str || ''); >+ >+ nodes = '<span>' + nodes + '</span>'; >+ return nodes; > } > }, > { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_home_library_id", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] > data: "home_library.name:me.home_library_id", > datatype: "coded_value:library", >- dataFilter: "libraries", >- className: "homebranch", > searchable: true, > orderable: true, >+ dataFilter: "libraries", >+ className: "location", >+ [% END %] > render: function (data, type, row, meta) { >- return escape_str(row._strings.home_library_id ? row._strings.home_library_id.str : row.home_library_id); >+ let nodes = ""; >+ let effective_home_library_id_str = row._strings.effective_home_library_id ? row._strings.effective_home_library_id.str : row.effective_home_library_id; >+ let home_library_id_str = row._strings.home_library_id ? row._strings.home_library_id.str : row.home_library_id; >+ >+ [% IF Koha.Preference('UseDisplayModule') %] >+ if (home_library_id_str != effective_home_library_id_str) { >+ nodes += '<a href="javascript:void(0)" onClick="handlePermanentLocation(this)" data-header="' + _("Permanent home branch") + '" data-body="' + home_library_id_str + '">'; >+ nodes += ' <i class="fa fa-info-circle" aria-hidden="true"></i>'; >+ nodes += '</a> '; >+ } >+ [% END %] >+ >+ nodes += escape_str(effective_home_library_id_str || ''); >+ >+ nodes = '<span>' + nodes + '</span>'; >+ return nodes; > } > }, > { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_location", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] > data: "me.location", >- datatype: "coded_value:location", > searchable: true, > orderable: true, >+ [% END %] > render: function (data, type, row, meta) { >- let nodes = '<span class="shelvingloc">'; >- [%# If permanent location is defined, show description or code and %] >- [%# display current location in parentheses. If not, display current location. %] >- [%# Note that permanent location is a code, and location may be an authval. %] >+ let nodes = ""; >+ let effective_loc_str = row._strings.effective_location ? row._strings.effective_location.str : row.effective_location; > let loc_str = row._strings.location ? row._strings.location.str : row.location; >- if ( row.permanent_location && row.permanent_location != row.location ) { >- let permanent_loc_str = av_loc.get(row.permanent_location); >- nodes += '%s (%s)'.format(escape_str(permanent_loc_str), escape_str(loc_str)); >- } else { >- nodes += escape_str(loc_str); >- } >- nodes += '</span>'; >+ >+ [% IF Koha.Preference('UseDisplayModule') %] >+ if (loc_str != effective_loc_str) { >+ nodes += '<a href="javascript:void(0)" onClick="handlePermanentLocation(this)" data-header="' + _("Permanent shelving location") + '" data-body="' + loc_str + '">'; >+ nodes += ' <i class="fa fa-info-circle" aria-hidden="true"></i>'; >+ nodes += '</a> '; >+ } >+ [% END %] >+ >+ nodes += escape_str(effective_loc_str || ''); >+ >+ nodes = '<span>' + nodes + '</span>'; > return nodes; > } > }, > { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_collection_code", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] > data: "me.collection_code", >- datatype: "coded_value:collection_code", > searchable: true, > orderable: true, >+ [% END %] > render: function (data, type, row, meta) { >- return escape_str(row._strings.collection_code ? row._strings.collection_code.str : row.collection_code); >+ let nodes = ""; >+ let effective_ccode_str = row._strings.effective_collection_code ? row._strings.effective_collection_code.str : row.effective_collection_code; >+ let ccode_str = row._strings.collection_code ? row._strings.collection_code.str : row.collection_code; >+ >+ [% IF Koha.Preference('UseDisplayModule') %] >+ if (ccode_str != effective_ccode_str) { >+ nodes += '<a href="javascript:void(0)" onClick="handlePermanentLocation(this)" data-header="' + _("Permanent collection") + '" data-body="' + ccode_str + '">'; >+ nodes += ' <i class="fa fa-info-circle" aria-hidden="true"></i>'; >+ nodes += '</a> '; >+ } >+ [% END %] >+ >+ nodes += escape_str(effective_ccode_str || ''); >+ >+ nodes = '<span>' + nodes + '</span>'; >+ return nodes; > } > }, > [% IF Koha.Preference('EnableItemGroups') %] >@@ -601,6 +704,7 @@ > } > } > [% END %] >+ > if ( status == 'available' ) { > nodes += ' <span>%s</span>'.format(_("Available")) > } >@@ -615,6 +719,28 @@ > return nodes; > } > }, >+ { >+ data: "me.displays", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ let nodes = ""; >+ >+ [% IF Koha.Preference('UseDisplayModule') && CAN_user_displays %] >+ displays.forEach(display => { >+ display.display_items.forEach(display_item => { >+ if (display_item.itemnumber === row.item_id) >+ nodes += '<li><span class="on_display"><a href="/cgi-bin/koha/display/displays/%s">%s</a></span></li>'.format(display.display_id, display.display_name); >+ }); >+ }); >+ >+ if (nodes != "") >+ nodes = '<ul>' + nodes + '</ul>'; >+ [% END %] >+ >+ return nodes; >+ } >+ }, > { > data: "me.last_seen_date", > type: "date", >@@ -744,19 +870,55 @@ > { > data: "me.public_notes", > className: "itemnotes", >+ [% IF Koha.Preference('UseDisplayModule') %] >+ searchable: false, >+ orderable: false, >+ [% ELSE %] > searchable: true, > orderable: true, >+ [% END %] > render: function (data, type, row, meta) { >- return row.public_notes ? escape_str(row.public_notes).replaceAll('\n', '<br />') : ''; >+ let nodes = ""; >+ >+ nodes = row.public_notes ? escape_str(row.public_notes).replaceAll('\n', '<br />') : ''; >+ >+ [% IF Koha.Preference('UseDisplayModule') %] >+ displays.forEach(display => { >+ display.display_items.forEach(display_item => { >+ if ((display_item.itemnumber === row.item_id) && (display.public_note)) >+ nodes += '<p><span class="public_note on_display">%s</span></p>'.format(display.public_note); >+ }); >+ }); >+ [% END %] >+ >+ return nodes; > } > }, > { > data: "me.internal_notes", > className: "nonpublicnote", >+ [% IF Koha.Preference('UseDisplayModule') %] >+ searchable: false, >+ orderable: false, >+ [% ELSE %] > searchable: true, > orderable: true, >+ [% END %] > render: function (data, type, row, meta) { >- return escape_str(row.internal_notes); >+ let nodes = ""; >+ >+ nodes = row.internal_notes ? escape_str(row.internal_notes) : ''; >+ >+ [% IF Koha.Preference('UseDisplayModule') %] >+ displays.forEach(display => { >+ display.display_items.forEach(display_item => { >+ if ((display_item.itemnumber === row.item_id) && (display.staff_note)) >+ nodes += '<p><span class="internal_note on_display">%s</span></p>'.format(display.staff_note); >+ }); >+ }); >+ [% END %] >+ >+ return nodes; > } > }, > [% IF Koha.Preference('EasyAnalyticalRecords') %] >@@ -920,6 +1082,18 @@ > }); > return items_table; > } >+ >+ const handlePermanentLocation = ((element) => { >+ const header = $(element).attr('data-header'); >+ const body = $(element).attr('data-body'); >+ >+ $('#permanant_location_modal_label').text(header); >+ $('#permanant_location_modal_body').html('<ul><li>' + body + '</li></ul>'); >+ $('#permanant_location_modal').modal('show'); >+ >+ return false; >+ }); >+ > function safe_link(uri,link_text) { > let node = document.createElement('a'); > let url_str = '#'; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc >index 535d6da6914..b7e5103831c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/permissions.inc >@@ -51,6 +51,9 @@ > [%- CASE 'coursereserves' -%] > <span class="main_permission coursereserves_permission">Course reserves</span> > <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'displays' -%] >+ <span class="main_permission displays_permission">Display module</span> >+ <span class="permissioncode">([% name | html %])</span> > [%- CASE 'plugins' -%] > <span class="main_permission plugins_permission">Koha plugins</span> > <span class="permissioncode">([% name | html %])</span> >@@ -520,6 +523,27 @@ > [%- CASE 'manage_courses' -%] > <span class="sub_permission manage_courses_subpermission"> Add, edit and delete courses </span> > <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'view_display' -%] >+ <span class="sub_permission view_display_subpermission"> View displays </span> >+ <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'add_display' -%] >+ <span class="sub_permission add_display_subpermission"> Add displays </span> >+ <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'edit_display' -%] >+ <span class="sub_permission edit_display_subpermission"> Edit displays </span> >+ <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'delete_display' -%] >+ <span class="sub_permission delete_display_subpermission"> Delete displays </span> >+ <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'add_items_to_display' -%] >+ <span class="sub_permission add_items_to_display_subpermission"> Add items to displays </span> >+ <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'add_items_to_display_from_any_libraries' -%] >+ <span class="sub_permission add_items_to_display_from_any_libraries_subpermission"> Add items to displays from any libraries </span> >+ <span class="permissioncode">([% name | html %])</span> >+ [%- CASE 'remove_items_from_display' -%] >+ <span class="sub_permission remove_items_from_display_subpermission"> Remove items from displays </span> >+ <span class="permissioncode">([% name | html %])</span> > [%- CASE 'configure' -%] > <span class="sub_permission configure_subpermission"> Configure plugins </span> > <span class="permissioncode">([% name | html %])</span> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc >index 2ba57981f4f..4df1eff7fbb 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/waiting_holds.inc >@@ -83,7 +83,7 @@ > </td> > <td>[% Branches.GetName( reserveloo.item.homebranch ) | html %]</td> > <td>[% Branches.GetName( reserveloo.item.holdingbranch ) | html %][% IF (reserveloo.desk_id ) %], [% reserveloo.desk.desk_name | html %][% END %]</td> >- <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => reserveloo.item.location) | html %]</td> >+ <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => reserveloo.item.effective_location ) | html %]</td> > <td>[% reserveloo.item.itemcallnumber | html %]</td> > <td>[% reserveloo.item.copynumber | html %]</td> > <td>[% reserveloo.item.enumchron | html %]</td> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/library_groups.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/library_groups.tt >index 059b66b9b04..d935408a52d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/library_groups.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/library_groups.tt >@@ -152,6 +152,12 @@ > Is local float group > </label> > </p> >+ <p> >+ <label> >+ <input type="checkbox" name="ft_display_group" id="add-group-modal-ft_display_group" value="1" /> >+ Is display group >+ </label> >+ </p> > </div> > </div> > </div> >@@ -235,6 +241,12 @@ > Is local float group > </label> > </p> >+ <p> >+ <label> >+ <input type="checkbox" id="edit-group-modal-ft_display_group" name="ft_display_group" value="1" /> >+ Is display group >+ </label> >+ </p> > </div> > </div> > </div> >@@ -331,7 +343,8 @@ > var ft_search_groups_staff = $(this).data("groupFt_search_groups_staff"); > var ft_local_hold_group = $(this).data("groupFt_local_hold_group"); > var ft_local_float_group = $(this).data("groupFt_local_float_group"); >- edit_group(id, parent_id, title, description, ft_hide_patron_info, ft_search_groups_opac, ft_search_groups_staff, ft_local_hold_group, ft_limit_item_editing, ft_local_float_group); >+ var ft_display_group = $(this).data("groupFt_display_group"); >+ edit_group(id, parent_id, title, description, ft_hide_patron_info, ft_search_groups_opac, ft_search_groups_staff, ft_local_hold_group, ft_limit_item_editing, ft_local_float_group, ft_display_group); > }); > > $(".delete-group").on("click", function (e) { >@@ -368,6 +381,7 @@ > $("#add-group-modal-ft_search_groups_staff").prop("checked", false); > $("#add-group-modal-ft_local_hold_group").prop("checked", false); > $("#add-group-modal-ft_local_float_group").prop("checked", false); >+ $("#add-group-modal-ft_display_group").prop("checked", false); > if (parent_id) { > $("#root-group-features-add").hide(); > } else { >@@ -376,7 +390,7 @@ > $("#add-group-modal").modal("show"); > } > >- function edit_group(id, parent_id, title, description, ft_hide_patron_info, ft_search_groups_opac, ft_search_groups_staff, ft_local_hold_group, ft_limit_item_editing, ft_local_float_group) { >+ function edit_group(id, parent_id, title, description, ft_hide_patron_info, ft_search_groups_opac, ft_search_groups_staff, ft_local_hold_group, ft_limit_item_editing, ft_local_float_group, ft_display_group) { > $("#edit-group-modal-id").val(id); > $("#edit-group-modal-title").val(title); > $("#edit-group-modal-description").val(description); >@@ -387,6 +401,7 @@ > $("#edit-group-modal-ft_search_groups_staff").prop("checked", false); > $("#edit-group-modal-ft_local_hold_group").prop("checked", false); > $("#edit-group-modal-ft_local_float_group").prop("checked", false); >+ $("#edit-group-modal-ft_display_group").prop("checked", false); > $("#root-group-features-edit").hide(); > } else { > $("#edit-group-modal-ft_hide_patron_info").prop("checked", ft_hide_patron_info ? true : false); >@@ -395,6 +410,7 @@ > $("#edit-group-modal-ft_search_groups_staff").prop("checked", ft_search_groups_staff ? true : false); > $("#edit-group-modal-ft_local_hold_group").prop("checked", ft_local_hold_group ? true : false); > $("#edit-group-modal-ft_local_float_group").prop("checked", ft_local_float_group ? true : false); >+ $("#edit-group-modal-ft_display_group").prop("checked", ft_display_group ? true : false); > $("#root-group-features-edit").show(); > } > >@@ -455,6 +471,9 @@ > [% IF group.ft_local_float_group %] > <li>Is local float group</li> > [% END %] >+ [% IF group.ft_display_group %] >+ <li>Is display group</li> >+ [% END %] > </ul> > [% END %] > </td> >@@ -486,6 +505,7 @@ > data-group-ft_local_hold_group="[% group.ft_local_hold_group | html %]" > data-group-ft_limit_item_editing="[% group.ft_limit_item_editing | html %]" > data-group-ft_local_float_group="[% group.ft_local_float_group | html %]" >+ data-group-ft_display_group="[% group.ft_display_group | html %]" > > > <i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit > </a> >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 29d80b0e20b..10d3e98a840 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 >@@ -1375,6 +1375,13 @@ Circulation: > 1: Use > 0: "Don't use" > - "course reserves." >+ Display module: >+ - >+ - pref: UseDisplayModule >+ choices: >+ 1: Use >+ 0: "Don't use" >+ - "the display module for managing item displays." > Batch checkout: > - > - pref: BatchCheckouts >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref >index 1861a0de4e6..c05dc2f8022 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/logs.pref >@@ -90,6 +90,12 @@ Logging: > 1: Log > 0: "Don't log" > - information from cron jobs. >+ - >+ - pref: DisplayItemsLog >+ choices: >+ 1: Log >+ 0: "Don't log" >+ - when displays are created, edited, deleted, or when items are added to or removed from displays. > - > - pref: ReportsLog > choices: >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tt >index c8a76b2f961..7ec0e402302 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/basket/basket.tt >@@ -243,7 +243,7 @@ > [% FOREACH ITEM_RESULT IN BIBLIO_RESULT.ITEM_RESULTS %] > <p> > [% Branches.GetName(ITEM_RESULT.holdingbranch) | html %] >- <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ITEM_RESULT.location ) | html %] </span> >+ <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ITEM_RESULT.effective_location ) | html %] </span> > [% IF ( ITEM_RESULT.itemcallnumber ) %] > ([% ITEM_RESULT.itemcallnumber | html %]) > [% END %] >@@ -337,7 +337,7 @@ > <span class="callnumber">[% ITEM_RESULT.itemcallnumber | html %]</span> > </strong> > [% Branches.GetName(ITEM_RESULT.holdingbranch) | html %] >- <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ITEM_RESULT.location ) | html %] </span> >+ <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ITEM_RESULT.effective_location ) | html %] </span> > </span> > </div> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >index 763cda06baf..2fd7eca2b20 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >@@ -1046,6 +1046,27 @@ > <!-- /#elasticPreview.modal --> > [% END %] > >+<div class="modal" id="permanent_location_modal" tabindex="-1" aria-labelledby="permanent_location_modal_label" aria-modal="true" role="dialog"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h1 class="modal-title" id="permanent_location_modal_label"></h1> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <div class="modal-body"> >+ <ul> >+ <li><span id="permanent_location_modal_body"></span></li> >+ </ul> >+ </div> >+ <div class="modal-footer"> >+ <button type="button" class="btn btn-default" data-bs-dismiss="modal">Close</button> >+ </div> >+ </div> >+ <!-- /.modal-content --> >+ </div> >+ <!-- /.modal-dialog --> >+</div> >+ > <div class="modal" id="modal-item-group-create" tabindex="-1" role="dialog" aria-labelledby="modal-item-group-create-label"> > <div class="modal-dialog"> > <div class="modal-content"> >@@ -1188,6 +1209,27 @@ > </div> > <!-- /#.modal --> > >+<!-- Permenant Location Modal --> >+<div class="modal" id="permanant_location_modal" tabindex="-1" aria-labelledby="permanant_location_modal_label" aria-hidden="true"> >+ <div class="modal-dialog"> >+ <div class="modal-content"> >+ <div class="modal-header"> >+ <h1 class="modal-title" id="permanant_location_modal_label"></h1> >+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> >+ </div> >+ <div class="modal-body"> >+ <div id="permanant_location_modal_body"></div> >+ </div> >+ <div class="modal-footer"> >+ <button type="button" class="btn btn-default" data-bs-dismiss="modal">Close</button> >+ </div> >+ </div> >+ <!-- /.modal-content --> >+ </div> >+ <!-- /.modal-dialog --> >+</div> >+<!-- /.modal --> >+ > [% IF bundlesEnabled %] > <div class="modal" id="addToBundleModal" tabindex="-1" role="dialog" aria-labelledby="addToBundleLabel"> > <div class="modal-dialog"> >@@ -2383,7 +2425,378 @@ > }); > > specific_dt_errors = _("Have a look at the 'Audit' button in the toolbar"); >+ >+ [% IF Koha.Preference('UseDisplayModule') && CAN_user_displays %] >+ // Display functionality >+ let availableDisplays = []; >+ let displayItemsTable = null; >+ let selectedDisplayItems = []; >+ >+ // Load displays on page load >+ $(document).ready(function() { >+ // Load available displays for dropdown >+ $.ajax({ >+ url: '/api/v1/displays', >+ method: 'GET', >+ headers: { 'x-koha-embed': 'display_items' }, >+ success: function(displays) { >+ availableDisplays = displays.filter(display => display.enabled); >+ updateDisplayDropdown(); >+ updateDisplaySelect(); >+ }, >+ error: function() { >+ $('#display-dropdown').html('<li class="text-center text-muted">Failed to load displays</li>'); >+ } >+ }); >+ }); >+ >+ function updateDisplayDropdown() { >+ const dropdown = $('#display-dropdown'); >+ if (availableDisplays.length === 0) { >+ dropdown.html('<li class="dropdown-item text-muted">No active displays available</li>'); >+ return; >+ } >+ >+ let html = ''; >+ availableDisplays.forEach(display => { >+ html += `<li><a class="dropdown-item" href="#" data-display-id="${display.display_id}" onclick="openDisplayModal(${display.display_id})">${display.display_name}</a></li>`; >+ }); >+ dropdown.html(html); >+ } >+ >+ function updateDisplaySelect() { >+ // Update display select >+ const displaySelect = $('#display-select'); >+ let selectHtml = '<option value="">Select a display</option>'; >+ availableDisplays.forEach(display => { >+ selectHtml += `<option value="${display.display_id}">${display.display_name}</option>`; >+ }); >+ displaySelect.html(selectHtml); >+ } >+ >+ function initializeDisplayItemsTable() { >+ if (displayItemsTable && displayItemsTable.DataTable) { >+ displayItemsTable.DataTable().destroy(); >+ displayItemsTable = null; >+ } >+ >+ selectedDisplayItems = []; >+ >+ // Use the same API endpoint and embed options as the main items table >+ let item_table_url = "/api/v1/biblios/[% biblionumber | uri %]/items?"; >+ let embed = ["+strings,_status,effective_home_library,effective_holding_library,home_library,holding_library"]; >+ >+ displayItemsTable = $("#display-items-table").kohaTable({ >+ ajax: { url: item_table_url }, >+ embed: embed, >+ order: [[1, 'asc']], // Sort by barcode >+ autoWidth: false, >+ paging: false, >+ searching: true, >+ info: false, >+ columns: [ >+ { >+ data: "me.item_id", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ return `<input type="checkbox" class="display-item-checkbox" value="${row.item_id}" data-item-id="${row.item_id}">`; >+ } >+ }, >+ { >+ data: "me.external_id", >+ searchable: true, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str(row.external_id || 'No barcode'); >+ } >+ }, >+ { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_holding_library_id", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] >+ data: "holding_library.name:me.holding_library_id", >+ datatype: "coded_value:library", >+ searchable: true, >+ orderable: true, >+ dataFilter: "libraries", >+ className: "location", >+ [% END %] >+ render: function (data, type, row, meta) { >+ let nodes = ""; >+ let effective_holding_library_id_str = row._strings.effective_holding_library_id ? row._strings.effective_holding_library_id.str : row.effective_holding_library_id; >+ let holding_library_id_str = row._strings.holding_library_id ? row._strings.holding_library_id.str : row.holding_library_id; >+ >+ nodes += escape_str(effective_holding_library_id_str || ''); >+ >+ [% IF Koha.Preference('UseDisplayModule') %] >+ if (holding_library_id_str != effective_holding_library_id_str) { >+ nodes += '<a href="javascript:void(0)" onClick="handlePermanentLocation(this)" data-header="Permanent holding branch" data-body="' + holding_library_id_str + '">'; >+ nodes += ' <i class="fa fa-info-circle" aria-hidden="true"></i>'; >+ nodes += '</a>'; >+ } >+ [% END %] >+ >+ nodes = '<span>' + nodes + '</span>'; >+ return nodes; >+ } >+ }, >+ { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_home_library_id", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] >+ data: "me.home_library_id", >+ searchable: true, >+ orderable: true, >+ [% END %] >+ render: function (data, type, row, meta) { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ let effective_home_library_id_str = row._strings.effective_home_library_id ? row._strings.effective_home_library_id.str : row.effective_home_library_id; >+ return escape_str(effective_home_library_id_str || ''); >+ [% ELSE %] >+ let home_library_id_str = row._strings.home_library_id ? row._strings.home_library_id.str : row.home_library_id; >+ return escape_str(home_library_id_str || ''); >+ [% END %] >+ } >+ }, >+ { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_location", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] >+ data: "me.location", >+ searchable: true, >+ orderable: true, >+ [% END %] >+ render: function (data, type, row, meta) { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ let loc_str = row._strings.effective_location ? row._strings.effective_location.str : row.effective_location; >+ return escape_str(effective_loc_str || ''); >+ [% ELSE %] >+ let loc_str = row._strings.location ? row._strings.location.str : row.location; >+ return escape_str(loc_str || ''); >+ [% END %] >+ } >+ }, >+ { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ data: "me.effective_collection_code", >+ searchable: false, >+ orderable: false, >+ [% ELSE %] >+ data: "me.collection_code", >+ searchable: true, >+ orderable: true, >+ [% END %] >+ render: function (data, type, row, meta) { >+ [% IF Koha.Preference('UseDisplayModule') %] >+ let effective_ccode_str = row._strings.effective_collection_code ? row._strings.effective_collection_code.str : row.effective_collection_code; >+ return escape_str(effective_ccode_str || ''); >+ [% ELSE %] >+ let ccode_str = row._strings.collection_code ? row._strings.collection_code.str : row.collection_code; >+ return escape_str(ccode_str || ''); >+ [% END %] >+ } >+ }, >+ { >+ data: "me.callnumber", >+ searchable: true, >+ orderable: true, >+ render: function (data, type, row, meta) { >+ return escape_str(row.callnumber || ''); >+ } >+ }, >+ { >+ data: "", >+ searchable: false, >+ orderable: false, >+ render: function (data, type, row, meta) { >+ let status = ''; >+ if (row._status && row._status.length > 0) { >+ status = row._status.map(s => s.replace(/_/g, ' ')).join(', '); >+ } else { >+ status = 'Available'; >+ } >+ return escape_str(status); >+ } >+ } >+ ], >+ [% IF Koha.Preference('UseDisplayModule') %] >+ rowCallback: function(row, data) { >+ // Hide items that are already on displays (effective_location starts with "DISPLAY:") >+ if (data.effective_location && data.effective_location.startsWith && data.effective_location.startsWith('DISPLAY:')) { >+ $(row).hide(); >+ return; >+ } >+ $(row).show(); >+ }, >+ [% END %] >+ drawCallback: function(settings) { >+ // Handle individual checkbox changes >+ $('.display-item-checkbox').off('change').on('change', function() { >+ const itemId = parseInt($(this).val()); >+ if ($(this).is(':checked')) { >+ if (!selectedDisplayItems.includes(itemId)) { >+ selectedDisplayItems.push(itemId); >+ } >+ } else { >+ selectedDisplayItems = selectedDisplayItems.filter(id => id !== itemId); >+ } >+ updateSelectAllState(); >+ }); >+ >+ // Handle select all checkbox >+ $('#select-all-display-items').off('change').on('change', function() { >+ const isChecked = $(this).is(':checked'); >+ $('.display-item-checkbox').prop('checked', isChecked); >+ >+ if (isChecked) { >+ selectedDisplayItems = []; >+ $('.display-item-checkbox').each(function() { >+ selectedDisplayItems.push(parseInt($(this).val())); >+ }); >+ } else { >+ selectedDisplayItems = []; >+ } >+ }); >+ } >+ }); >+ } >+ >+ function updateSelectAllState() { >+ const totalCheckboxes = $('.display-item-checkbox').length; >+ const checkedCheckboxes = $('.display-item-checkbox:checked').length; >+ >+ if (checkedCheckboxes === 0) { >+ $('#select-all-display-items').prop('indeterminate', false).prop('checked', false); >+ } else if (checkedCheckboxes === totalCheckboxes) { >+ $('#select-all-display-items').prop('indeterminate', false).prop('checked', true); >+ } else { >+ $('#select-all-display-items').prop('indeterminate', true); >+ } >+ } >+ >+ function openDisplayModal(displayId = null) { >+ if (displayId) { >+ $('#display-select').val(displayId); >+ } >+ // Initialize the DataTable when the modal is opened >+ initializeDisplayItemsTable(); >+ $('#addToDisplayModal').modal('show'); >+ } >+ >+ // Clear date button functionality >+ $('#clear-date').on('click', function() { >+ $('#date-remove').val(''); >+ }); >+ >+ // Form submission >+ $('#addToDisplayForm').on('submit', function(e) { >+ e.preventDefault(); >+ >+ const displayId = $('#display-select').val(); >+ const removeDate = $('#date-remove').val(); >+ >+ if (!displayId) { >+ alert('Please select a display'); >+ return; >+ } >+ >+ if (selectedDisplayItems.length === 0) { >+ alert('Please select at least one item'); >+ return; >+ } >+ >+ $('#add-to-display-btn').prop('disabled', true).text('Adding...'); >+ >+ // Add each item to the display >+ let promises = selectedDisplayItems.map(itemId => { >+ const data = { >+ display_id: parseInt(displayId), >+ itemnumber: parseInt(itemId), >+ biblionumber: [% biblionumber | html %], >+ date_added: new Date().toISOString().split('T')[0] >+ }; >+ if (removeDate) { >+ data.date_remove = removeDate; >+ } >+ >+ return $.ajax({ >+ url: '/api/v1/display/items', >+ method: 'POST', >+ contentType: 'application/json', >+ data: JSON.stringify(data) >+ }); >+ }); >+ >+ Promise.all(promises).then(() => { >+ alert(`Successfully added ${selectedDisplayItems.length} item(s) to display`); >+ $('#addToDisplayModal').modal('hide'); >+ $('#addToDisplayForm')[0].reset(); >+ selectedDisplayItems = []; >+ >+ // Safely refresh modal table >+ try { >+ if (displayItemsTable && displayItemsTable.DataTable) { >+ displayItemsTable.DataTable().draw(); >+ } >+ } catch (e) { >+ // Modal table refresh failed - not critical >+ } >+ >+ // Safely refresh the main items table to show updated locations >+ try { >+ if (typeof build_items_table === 'function') { >+ $('.items_table').each(function() { >+ let table_id = $(this).attr('id').replace('_table', ''); >+ build_items_table(table_id, false, { destroy: true }); >+ }); >+ } >+ } catch (e) { >+ // Main table refresh failed - reload page as fallback >+ window.location.reload(); >+ } >+ }).catch((error) => { >+ console.error('Error adding items to display:', error); >+ alert('Failed to add some items to display. Please try again.'); >+ }).finally(() => { >+ $('#add-to-display-btn').prop('disabled', false).text('Add to display'); >+ }); >+ }); >+ >+ // Clean up when modal is hidden >+ $('#addToDisplayModal').on('hidden.bs.modal', function() { >+ if (displayItemsTable && displayItemsTable.DataTable) { >+ displayItemsTable.DataTable().destroy(); >+ displayItemsTable = null; >+ } >+ selectedDisplayItems = []; >+ $('#addToDisplayForm')[0].reset(); >+ }); >+ [% END %] > </script> > [% CoverImagePlugins | $raw %] > [% END # /jsinclude %] >+ >+[% BLOCK cssinclude %] >+ <style> >+ .display-location { >+ font-weight: bold; >+ color: #d9534f; >+ } >+ .display-location::before { >+ content: "\1F4FA "; >+ font-size: 0.8em; >+ } >+ .original-location { >+ font-size: 0.9em; >+ font-style: italic; >+ } >+ </style> >+[% END %] > [% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt >index f9313d0dd20..6b52cf975bc 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt >@@ -187,10 +187,23 @@ > [% IF ( ITEM_DAT.displaycopy ) %] > <li class="copynumber"><span class="label">Copy number:</span> [% ITEM_DAT.copyvol | html %] </li> > [% END %] >- [% IF ( ITEM_DAT.location ) %] >+ [% IF ( ITEM_DAT.effective_location ) %] > <li class="location"> > <span class="label">Shelving location:</span> >- [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ITEM_DAT.location ) | html %] >+ [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ITEM_DAT.effective_location ) | html %] >+ </li> >+ [% END %] >+ [% IF ( ITEM_DAT.displays ) %] >+ <li class="displays" class="nowrap"> >+ [% IF ITEM_DAT.displays.size > 1 %] >+ <span class="label">In displays:</span> >+ [% ELSE %] >+ <span class="label">In display:</span> >+ [% END %] >+ [% FOR display IN ITEM_DAT.displays %] >+ <a href="/cgi-bin/koha/display/displays/[% display.display_id | url %]">[% display.display_name | html %]</a> >+ [% UNLESS loop.last %],[% END %] >+ [% END %] > </li> > [% END %] > [% IF ( ITEM_DAT.replacementprice ) %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt >index 6ac67649634..f8a00a21080 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/results.tt >@@ -860,6 +860,16 @@ > [% END %] > <span class="item_count">[% items_loo.count | html %]</span> > </div> >+ [% IF ( items_loo.displays ) %] >+ <span class="displays" >+ >In display(s): >+ <ul> >+ [% FOR display IN items_loo.displays %] >+ <li><a href="/cgi-bin/koha/display/displays/[% display.display_id | url %]">[% display.display_name | html %]</a></li> >+ [% END %] >+ </ul> >+ </span> >+ [% END %] > <!-- /.result_item_details --> > > [% IF status_count == "onloancount" %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt >index 0e6c6a6c812..ea42d7b0f9a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt >@@ -5,6 +5,7 @@ > [% USE KohaDates %] > [% USE Price %] > [% USE Item %] >+[% USE AuthorisedValues %] > [% USE TablesSettings %] > [% PROCESS 'i18n.inc' %] > [% INCLUDE 'doc-head-open.inc' %] >@@ -86,6 +87,19 @@ > <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber | uri %]#holdings">go to the records holdings</a>. > </div> > [% END %] >+ [% IF ( items ) %] >+ [% FOREACH item IN items %] >+ [% IF item.ondisplay %] >+ <div class="alert alert-warning"> >+ <p> <strong>Item(s) on display:</strong> The following item is currently on display, and cannot be modified: </p> >+ <ul> >+ <li><a href="/cgi-bin/koha/display/displays/[% item.active_display_id | url %]">[% item.barcode | html %]</a></li> >+ </ul> >+ <p> The permanent location for these item(s) is found below. To modify these details, edit the display, or remove the item from the display. </p> >+ </div> >+ [% END %] >+ [% END %] >+ [% END %] > <h1>Items for [% biblio.title | html %] [% IF ( biblio.author ) %]by [% biblio.author | html %][% END %] (Record #[% biblio.biblionumber | html %])</h1> > <a id="newitem_jump" href="#f"><i class="fa fa-arrow-down"></i> Jump to form</a> > >@@ -104,7 +118,7 @@ > [% IF item_not_found %]<div class="alert alert-warning"><strong>Cannot delete</strong>: Item not found.</div>[% END %] > > <div id="cataloguing_additem_itemlist"> >- [% IF items %] >+ [% IF ( items ) %] > [% SET date_fields = [ 'dateaccessioned', 'onloan', 'datelastseen', 'datelastborrowed', 'replacementpricedate' ] %] > <div class="page-section"> > <table id="itemst"> >@@ -118,7 +132,7 @@ > </thead> > <tbody> > [% FOREACH item IN items %] >- [% SET can_be_edited = ! ( Koha.Preference('IndependentBranches') && ! logged_in_user.is_superlibrarian && item.homebranch != Branches.GetLoggedInBranchname() ) %] >+ [% SET can_be_edited = ! ( ( Koha.Preference('IndependentBranches') && ! logged_in_user.is_superlibrarian && item.homebranch != Branches.GetLoggedInBranchname() ) || ( item.nomod ) ) %] > [% SET tr_class = '' %] > [% IF item.itemnumber == itemnumber AND op == 'cud-saveitem' %] > [% UNLESS can_be_edited %] >@@ -131,7 +145,18 @@ > [% END %] > <tr id="row[% item.itemnumber | html %]" class="[% tr_class | html %]"> > [% UNLESS can_be_edited %] >- <td> </td> >+ [% IF ( item.ondisplay ) %] >+ <td> >+ <em>Item on display:</em> >+ <ul> >+ <li> >+ <em><a href="/cgi-bin/koha/display/displays/[% item.active_display_id | url %]">[% item.active_display_name | html %]</a></em> >+ </li> >+ </ul> >+ </td> >+ [% ELSE %] >+ <td> </td> >+ [% END %] > [% ELSE %] > <td> > <div class="btn-group dropup"> >@@ -214,6 +239,8 @@ > <td class="[% can_mod | html %]" data-order="[% item.$attribute | html %]">[% item.$attribute | $Price %]</td> > [% ELSIF item.$attribute && attribute == 'itemcallnumber' %] > <td class="[% can_mod | html %]" data-order="[% item.cn_sort | html %]">[% item.$attribute | html %]</td> >+ [% ELSIF attribute == 'location' %] >+ <td class="[% can_mod | html %]"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.location ) | html %] </td> > [% ELSE %] > <td class="[% can_mod | html %]">[% item.$attribute | html %]</td> > [% END %] >@@ -291,128 +318,138 @@ > </div> > [% END %] > >- <fieldset class="rows"> [% PROCESS subfields_for_item subfields => subfields %] </fieldset> >- [% IF op != 'cud-additem' %] >- <input type="hidden" name="itemnumber" value="[% itemnumber | html %]" /> >- [% END %] >+ [% UNLESS ( nomod ) %] >+ <fieldset class="rows"> [% PROCESS subfields_for_item subfields => subfields %] </fieldset> >+ [% IF op != 'cud-additem' %] >+ <input type="hidden" name="itemnumber" value="[% itemnumber | html %]" /> >+ [% END %] > >- [% IF item_groups.size && op != 'cud-saveitem' && CAN_user_editcatalogue_manage_item_groups %] >- <fieldset class="rows"> >- <legend><i class="fa fa-plus"></i> Add to item group</legend> >- [% FOREACH ig IN item_groups %] >- <input type="hidden" id="item-group-[% ig.id | html %]" value="[% ig.description | html %]" /> >- [% END %] >- <ol> >- <li> >- <label for="select_item_group">Options: </label> >- <select name="item_group" id="item-group-add-or-create-form-select"> >- <optgroup label="Use existing item group"> >- [% FOREACH ig IN biblio.item_groups.search({}, {order_by => 'display_order'}) %] >- <option value="[% ig.id | html %]">[% ig.description | html %]</option> >- [% END %] >- </optgroup> >- <optgroup label="Other options"> >- <option id="item-group-add-or-create-form-no-add" value="">Do not add to item group</option> >- <option value="create">Create new item group</option> >- </optgroup> >- </select> >- </li> >- <div id="item-group-add-or-create-form-description-block"> >- <li> >- <label for="item_group_description" class="required">Name: </label> >- <input name="item_group_description" id="item-group-add-or-create-form-description" type="text" size="30" class="required" /> >- <span class="required">Required</span> >- </li> >+ [% IF item_groups.size && op != 'cud-saveitem' && CAN_user_editcatalogue_manage_item_groups %] >+ <fieldset class="rows"> >+ <legend><i class="fa fa-plus"></i> Add to item group</legend> >+ [% FOREACH ig IN item_groups %] >+ <input type="hidden" id="item-group-[% ig.id | html %]" value="[% ig.description | html %]" /> >+ [% END %] >+ <ol> > <li> >- <label for="item_group_display_order">Display order: </label> >- <input name="item_group_display_order" id="item_group_display_order" type="text" pattern="\d*" size="30" /> >- <div class="hint">Display order must be numerical</div> >+ <label for="select_item_group">Options: </label> >+ <select name="item_group" id="item-group-add-or-create-form-select"> >+ <optgroup label="Use existing item group"> >+ [% FOREACH ig IN biblio.item_groups.search({}, {order_by => 'display_order'}) %] >+ <option value="[% ig.id | html %]">[% ig.description | html %]</option> >+ [% END %] >+ </optgroup> >+ <optgroup label="Other options"> >+ <option id="item-group-add-or-create-form-no-add" value="">Do not add to item group</option> >+ <option value="create">Create new item group</option> >+ </optgroup> >+ </select> > </li> >- </div> >- </ol> >- </fieldset> >- [% END %] >- >- <fieldset class="action"> >- [% IF op != 'cud-saveitem' %] >- <input type="submit" name="phony_submit" value="phony_submit" id="phony_submit" style="display:none;" onclick="return false;" /> >- <!-- Note: >- We use here a false submit button because we have several submit buttons and we do not want the user to believe they validated the adding of multiple items >- when pressing the enter key, while in fact it is the first submit button that is validated, in our case the "add (single) item" button. >- It is a bit tricky, but necessary in the sake of UI correctness. >- --> >- <span id="addsingle"> >- <input type="submit" name="add_submit" value="Add item" onclick="return Check(this.form)" /> >- <input type="submit" name="add_duplicate_submit" value="Add and duplicate" onclick="return Check(this.form)" /> >- </span> >- <span id="addmultiple"> >- <input type="button" name="add_multiple_copies" id="add_multiple_copies" value="Add multiple copies of this item" /> >- </span> >- <fieldset id="add_multiple_copies_span"> >- <label for="number_of_copies">Number of copies of this item to add: </label> >- <input type="text" id="number_of_copies" name="number_of_copies" value="" size="2" maxlength="3" /> >- <input type="submit" id="add_multiple_copies_submit" name="add_multiple_copies_submit" value="Add" onclick="javascript:return Check(this.form) && CheckMultipleAdd(this.form.number_of_copies.value);" /> >- <a href="#" id="cancel_add_multiple" class="cancel">Cancel</a> >- <div class="hint"><p>Maximum currently set to 1000. The barcode you enter will be incremented for each additional item.</p></div> >+ <div id="item-group-add-or-create-form-description-block"> >+ <li> >+ <label for="item_group_description" class="required">Name: </label> >+ <input name="item_group_description" id="item-group-add-or-create-form-description" type="text" size="30" class="required" /> >+ <span class="required">Required</span> >+ </li> >+ <li> >+ <label for="item_group_display_order">Display order: </label> >+ <input name="item_group_display_order" id="item_group_display_order" type="text" pattern="\d*" size="30" /> >+ <div class="hint">Display order must be numerical</div> >+ </li> >+ </div> >+ </ol> > </fieldset> >+ [% END %] > >- <span id="savetemplate"> >- <input type="button" name="save_as_template" id="save_as_template" value="Save as template" /> >- </span> >- <fieldset id="save_as_template_span"> >- <legend>Save template</legend> >- <div class="btn-group"> >- <select name="replace_template_id" id="replace_template_id" class="select2" style="width: 20em"> >- <option value="0" selected="selected">Save as new template</option> >- <optgroup label="Update existing template"> >- [% FOREACH t IN item_templates.owned %] >- <option data-editor="1" data-shared="[% t.is_shared | html %]" value="[% t.id | html %]">[% t.name | html %][% IF t.is_shared %](shared)[% END %]</option> >- [% END %] >- [% IF CAN_user_editcatalogue_manage_item_editor_templates && item_templates.shared.count %] >- <optgroup label="Update shared template"> >- [% FOREACH t IN item_templates.shared %] >- <option data-editor="1" data-shared="1" value="[% t.id | html %]">[% t.name | html %][% IF t.is_shared %](shared)[% END %]</option> >- [% END %] >- </optgroup> >- [% END %] >- </optgroup> >- </select> >- </div> >+ <fieldset class="action"> >+ [% IF op != 'cud-saveitem' %] >+ <input type="submit" name="phony_submit" value="phony_submit" id="phony_submit" style="display:none;" onclick="return false;" /> >+ <!-- Note: >+ We use here a false submit button because we have several submit buttons and we do not want the user to believe they validated the adding of multiple items >+ when pressing the enter key, while in fact it is the first submit button that is validated, in our case the "add (single) item" button. >+ It is a bit tricky, but necessary in the sake of UI correctness. >+ --> >+ <span id="addsingle"> >+ <input type="submit" name="add_submit" value="Add item" onclick="return Check(this.form)" /> >+ <input type="submit" name="add_duplicate_submit" value="Add and duplicate" onclick="return Check(this.form)" /> >+ </span> >+ <span id="addmultiple"> >+ <input type="button" name="add_multiple_copies" id="add_multiple_copies" value="Add multiple copies of this item" /> >+ </span> >+ <fieldset id="add_multiple_copies_span"> >+ <label for="number_of_copies">Number of copies of this item to add: </label> >+ <input type="text" id="number_of_copies" name="number_of_copies" value="" size="2" maxlength="3" /> >+ <input >+ type="submit" >+ id="add_multiple_copies_submit" >+ name="add_multiple_copies_submit" >+ value="Add" >+ onclick="javascript:return Check(this.form) && CheckMultipleAdd(this.form.number_of_copies.value);" >+ /> >+ <a href="#" id="cancel_add_multiple" class="cancel">Cancel</a> >+ <div class="hint"><p>Maximum currently set to 1000. The barcode you enter will be incremented for each additional item.</p></div> >+ </fieldset> > >- <div class="btn-group"> >- <span id="template_name_block"> >- <label for="template_name" class="required">Template name: </label> >- <input type="text" id="template_name" name="template_name" class="required" /> >- <span class="required">Required</span> >- </span> >- </div> >+ <span id="savetemplate"> >+ <input type="button" name="save_as_template" id="save_as_template" value="Save as template" /> >+ </span> >+ <fieldset id="save_as_template_span"> >+ <legend>Save template</legend> >+ <div class="btn-group"> >+ <select name="replace_template_id" id="replace_template_id" class="select2" style="width: 20em"> >+ <option value="0" selected="selected">Save as new template</option> >+ <optgroup label="Update existing template"> >+ [% FOREACH t IN item_templates.owned %] >+ <option data-editor="1" data-shared="[% t.is_shared | html %]" value="[% t.id | html %]">[% t.name | html %][% IF t.is_shared %](shared)[% END %]</option> >+ [% END %] >+ [% IF CAN_user_editcatalogue_manage_item_editor_templates && item_templates.shared.count %] >+ <optgroup label="Update shared template"> >+ [% FOREACH t IN item_templates.shared %] >+ <option data-editor="1" data-shared="1" value="[% t.id | html %]">[% t.name | html %][% IF t.is_shared %](shared)[% END %]</option> >+ [% END %] >+ </optgroup> >+ [% END %] >+ </optgroup> >+ </select> >+ </div> > >- <div class="btn-group"> >- <label for="template_is_shared"> >- <input type="checkbox" id="template_is_shared" name="template_is_shared" /> >- Share template >- </label> >- </div> >+ <div class="btn-group"> >+ <span id="template_name_block"> >+ <label for="template_name" class="required">Template name: </label> >+ <input type="text" id="template_name" name="template_name" class="required" /> >+ <span class="required">Required</span> >+ </span> >+ </div> > >- <div class="btn-group"> >- <input type="submit" id="save_as_template_submit" name="save_as_template_submit" value="Save" onclick="javascript:return CheckTemplateForm(this.form);" /> >- <a href="#" id="cancel_save_as_template" class="cancel">Cancel</a> >- </div> >- </fieldset> >- [% ELSE %] >- [% IF op != 'add_item' %] >- <input type="hidden" name="itemnumber" value="[% itemnumber | html %]" /> >- [% END %] >- [% IF Item.HasSerialItem(itemnumber) == 0 %] >- <input type="submit" value="Save changes" onclick="return Check(this.form)" /> >+ <div class="btn-group"> >+ <label for="template_is_shared"> >+ <input type="checkbox" id="template_is_shared" name="template_is_shared" /> >+ Share template >+ </label> >+ </div> >+ >+ <div class="btn-group"> >+ <input type="submit" id="save_as_template_submit" name="save_as_template_submit" value="Save" onclick="javascript:return CheckTemplateForm(this.form);" /> >+ <a href="#" id="cancel_save_as_template" class="cancel">Cancel</a> >+ </div> >+ </fieldset> > [% ELSE %] >- <input type="button" class="submit" value="Save changes" onclick="return ShowSerialEditingConfirmation(this.form)" /> >- <input type="hidden" name="edit-serial-issue" id="edit-serial-issue" value /> >+ [% IF op != 'add_item' %] >+ <input type="hidden" name="itemnumber" value="[% itemnumber | html %]" /> >+ [% END %] >+ [% IF Item.HasSerialItem(itemnumber) == 0 %] >+ <input type="submit" value="Save changes" onclick="return Check(this.form)" /> >+ [% ELSE %] >+ <input type="button" class="submit" value="Save changes" onclick="return ShowSerialEditingConfirmation(this.form)" /> >+ <input type="hidden" name="edit-serial-issue" id="edit-serial-issue" value /> >+ [% END %] >+ <input type="button" id="addnewitem" value="Add a new item" /> >+ <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber | uri %]">Cancel</a> > [% END %] >- <input type="button" id="addnewitem" value="Add a new item" /> >- <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber | uri %]">Cancel</a> >- [% END %]</fieldset >- > >+ </fieldset> >+ [% ELSE %] >+ <em>This item is not presently editable. Please check the alert dialog above for details.</em> >+ [% END %] > > [%# Fields for fast cataloging %] > <input type="hidden" name="circborrowernumber" value="[% circborrowernumber | html %]" /> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/article-requests.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/article-requests.tt >index cfb47daa5c4..6c5e89c3427 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/article-requests.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/article-requests.tt >@@ -273,8 +273,8 @@ > <td class="ar-collection">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => ar.item.ccode ) | html %]</td> > <td class="ar-itemtype">[% ItemTypes.GetDescription( ar.item.effective_itemtype ) | html %]</td> > <td class="ar-callnumber"> >- [% IF ar.item.location %] >- <em>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ar.item.location ) | html %]</em> >+ [% IF ar.item.effective_location %] >+ <em>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ar.item.effective_location ) | html %]</em> > [% END %] > > [% ar.item.itemcallnumber | html %] >@@ -380,8 +380,8 @@ > <td class="ar-collection">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => ar.item.ccode ) | html %]</td> > <td class="ar-itemtype">[% ItemTypes.GetDescription( ar.item.effective_itemtype ) | html %]</td> > <td class="ar-callnumber"> >- [% IF ar.item.location %] >- <em>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ar.item.location ) | html %]</em> >+ [% IF ar.item.effective_location %] >+ <em>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ar.item.effective_location ) | html %]</em> > [% END %] > > [% ar.item.itemcallnumber | html %] >@@ -484,8 +484,8 @@ > <td class="ar-collection">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => ar.item.ccode ) | html %]</td> > <td class="ar-itemtype">[% ItemTypes.GetDescription( ar.item.effective_itemtype ) | html %]</td> > <td class="ar-callnumber"> >- [% IF ar.item.location %] >- <em>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ar.item.location ) | html %]</em> >+ [% IF ar.item.effective_location %] >+ <em>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => ar.item.effective_location ) | html %]</em> > [% END %] > > [% ar.item.itemcallnumber | html %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/branchtransfers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/branchtransfers.tt >index c03e8ee439c..63ac4df702a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/branchtransfers.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/branchtransfers.tt >@@ -274,7 +274,7 @@ > >[% trsfitemloo.item.barcode | html %]</a > ></td > > >- <td class="tf-location"><span class="shelvingloc">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => trsfitemloo.item.location ) | html %]</span></td> >+ <td class="tf-location"><span class="shelvingloc">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => trsfitemloo.item.effective_location ) | html %]</span></td> > <td class="tf-itemcallnumber">[% trsfitemloo.item.itemcallnumber | html %]</td> > <td class="tf-itemtype">[% ItemTypes.GetDescription( trsfitemloo.item.effective_itemtype ) | html %]</td> > <td class="tf-ccode">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => trsfitemloo.item.ccode ) | html %]</td> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/on-site_checkouts.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/on-site_checkouts.tt >index bb315fd622f..14b5b7fe7c7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/on-site_checkouts.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/on-site_checkouts.tt >@@ -63,7 +63,7 @@ > <a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% item.biblionumber | uri %]&itemnumber=[% item.itemnumber | uri %]#item[% item.itemnumber | uri %]">[% item.barcode | html %]</a> > </td> > <td>[% Branches.GetName(item.branchcode) | html %]</td> >- <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.location ) | html %]</td> >+ <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => (item.effective_location || item.location) ) | html %]</td> > </tr> > [% END %] > </tbody> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/overdue.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/overdue.tt >index 1bc2b58b50d..1f62dcc3163 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/overdue.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/overdue.tt >@@ -144,7 +144,7 @@ > > > <td>[% Branches.GetName( overdueloo.homebranchcode ) | html %]</td> > <td>[% Branches.GetName( overdueloo.holdingbranchcode ) | html %]</td> >- <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => overdueloo.location ) | html %]</td> >+ <td> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => overdueloo.effective_location ) | html %] </td> > <td data-order="[% overdueloo.datelastborrowed | html %]">[% overdueloo.datelastborrowed | $KohaDates %]</td> > <td > ><a href="/cgi-bin/koha/catalogue/moredetail.pl?biblionumber=[% overdueloo.biblionumber | uri %]&itemnumber=[% overdueloo.itemnum | uri %]#item[% overdueloo.itemnum | uri %]" >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt >index 6b008e35045..f4169e14c8b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingbookings.tt >@@ -235,16 +235,16 @@ > } > }, > { >- data: "item.location", >- title: _("Location"), >- searchable: false, >- orderable: false, >+ "data": "item.effective_location", >+ "title": _("Location"), >+ "searchable": false, >+ "orderable": false, > render: function(data,type,row,meta) { > if ( row.item ) { > if ( row.item.checked_out_date ) { > return _("On loan, due: ") + $date(row.item.checked_out_date); > } else { >- return row.item._strings.location.str; >+ return row.item._strings.effective_location.str; > } > } else { > return null; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt >index 2b74dbe86c7..c6d79b5d2e9 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt >@@ -80,6 +80,7 @@ > <th class="string-sort">Available item types</th> > <th class="string-sort">Available locations</th> > <th class="string-sort">Available collections</th> >+ <th class="string-sort">Displays</th> > <th>Earliest hold date</th> > <th>Hold notes</th> > <th class="string-sort">Pickup location</th> >@@ -196,6 +197,15 @@ > [% END %] > </ul> > </td> >+ <td> >+ [% IF ( hold_info.displays.size ) %] >+ <ul> >+ [% FOREACH display IN hold_info.displays %] >+ <li><a href="/cgi-bin/koha/display/displays/[% display.display_id | url %]">[% display.display_name | html %]</a></li> >+ [% END %] >+ </ul> >+ [% END %] >+ </td> > <td data-order="[% hold.reservedate | html %]"> [% hold.reservedate | $KohaDates %] in [% Branches.GetName ( hold.branchcode ) | html %] </td> > <td>[% hold.reservenotes | html %]</td> > <td> [% Branches.GetName ( hold.branchcode ) | html %] </td> >@@ -322,8 +332,17 @@ > pickup_locations : (table_dt) => get_options(table_dt.column(15)), > }; > >- > var table_settings = [% TablesSettings.GetTableSettings('circ', 'holds', 'holds-to-pull', 'json') | $raw %]; >+ >+ [% UNLESS Koha.Preference('UseDisplayModule') %] >+ table_settings.columns = table_settings.columns.map((element, idx) => { >+ if(element.columnname == "displays") >+ element.is_hidden = 1; >+ >+ return element; >+ }); >+ [% END %] >+ > var holdst = $("#holdst").kohaTable( > { > pagingType: "full_numbers", >@@ -341,6 +360,7 @@ > {name: "itemtypes", dataFilter: "item_types" }, > {name: "locations", dataFilter: "locations" }, > {name: "collection" }, >+ {name: "displays" }, > {name: "hold_date" }, > {name: "reserve_nodes" }, > {name: "pickup_location", dataFilter: "pickup_locations" }, >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >index 5d3cc6975f6..b50629dda6d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >@@ -269,6 +269,13 @@ > </div> > [% END %] > >+ [% IF RemovedFromDisplay %] >+ <div id="removed_from_display" class="alert alert-info"> >+ <h3>Item removed from display</h3> >+ <p>This item has been removed from the display: <strong>[% RemovedFromDisplay.display_name | html %]</strong></p> >+ </div> >+ [% END %] >+ > [% IF ( errmsgloop ) %] > <div class="alert alert-warning audio-alert-warning"> > <h3>Check in message</h3> >@@ -1385,7 +1392,7 @@ > [%- END -%] > </td> > <td class="ci-shelvinglocation"> >- <span class="shelvingloc">[% checkin.item_location | html %]</span> >+ <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => checkin.item.effective_location ) | html %] </span> > </td> > <td class="ci-callnumber"> [% checkin.item.itemcallnumber | html %] </td> > <td class="ci-dateaccessioned"> [% checkin.item.dateaccessioned | $KohaDates %] </td> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt >index facdba84331..a9e40cc1c3d 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/view_holdsqueue.tt >@@ -113,6 +113,9 @@ > <th class="hq-collection">Collection</th> > <th class="hq-location">Shelving location</th> > <th class="hq-itemtype">Item type</th> >+ [% IF Koha.Preference('UseDisplayModule') %] >+ <th class="hq-displays">Displays</th> >+ [% END %] > <th class="hq-callnumber">Call number</th> > <th class="hq-copynumber">Copy number</th> > <th class="hq-enumchron">Enumeration</th> >@@ -164,6 +167,13 @@ > <input type="text" placeholder="Item type" /> > </span> > </td> >+ [% IF Koha.Preference('UseDisplayModule') %] >+ <td class="hq-displays"> >+ <span class="filter_column filter_text"> >+ <input type="text" placeholder="Displays" /> >+ </span> >+ </td> >+ [% END %] > <td class="hq-callnumber"> > <span class="filter_column filter_text"> > <input type="text" placeholder="Call number" /> >@@ -211,8 +221,11 @@ > </td> > </tr> > </thead> >- <tbody >- >[% FOREACH itemsloo IN itemsloop %] >+ <tbody> >+ [% FOREACH itemsloo IN itemsloop %] >+ [% SET displays = itemsloo.displays %] >+ [% SET display_items = itemsloo.display_items %] >+ [% SET itemsloo = itemsloo.object %] > <tr> > <td class="hq-title"> > <p> [% INCLUDE 'biblio-title.inc' biblio=itemsloo.biblio link = 1 %] </p> >@@ -237,11 +250,20 @@ > [% IF ( itemsloo.biblio.biblioitem.isbn ) %]<span>ISBN: [% itemsloo.biblio.biblioitem.isbn | html %]</span>[% END %] > </div> > </td> >- <td class="hq-holdingbranch">[% Branches.GetName( itemsloo.holdingbranch ) | html %]</td> >- <td class="hq-homebranch">[% Branches.GetName( itemsloo.item.homebranch ) | html %]</td> >- <td class="hq-collection">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => itemsloo.item.ccode ) | html %]</td> >- <td class="hq-location">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => itemsloo.item.location ) | html %]</td> >+ <td class="hq-holdingbranch">[% itemsloo.item.effective_holdingbranch.branchname | html %]</td> >+ <td class="hq-homebranch">[% itemsloo.item.effective_homebranch.branchname | html %]</td> >+ <td class="hq-collection">[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => itemsloo.item.effective_collection_code ) | html %]</td> >+ <td class="hq-location"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => itemsloo.item.effective_location ) | html %] </td> > <td class="hq-itemtype">[% ItemTypes.GetDescription( itemsloo.item.effective_itemtype ) | html %]</td> >+ [% IF Koha.Preference('UseDisplayModule') %] >+ <td class="hq-displays"> >+ <ul> >+ [% FOREACH display IN displays %] >+ <li><a href="/cgi-bin/koha/display/displays/[% display.display_id | url %]" target="_blank">[% display.display_name | html %]</a></li> >+ [% END %] >+ </ul> >+ </td> >+ [% END %] > <td class="hq-callnumber"><span class="itemcallnumber">[% itemsloo.item.itemcallnumber | html %]</span></td> > <td class="hq-copynumber">[% itemsloo.item.copynumber | html %]</td> > <td class="hq-enumchron">[% itemsloo.item.enumchron | html %]</td> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/display/display-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/display/display-home.tt >new file mode 100644 >index 00000000000..1c5fe28c516 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/display/display-home.tt >@@ -0,0 +1,36 @@ >+[% USE raw %] >+[% USE To %] >+[% USE Asset %] >+[% USE Koha %] >+[% USE KohaDates %] >+[% USE TablesSettings %] >+[% USE AuthorisedValues %] >+[% SET footerjs = 1 %] >+[% PROCESS 'i18n.inc' %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title> Displays › Koha </title> >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+ >+<body id="display_home" class="display"> >+[% WRAPPER 'header.inc' %] >+ [% INCLUDE 'display-search.inc' %] >+[% END %] >+ >+<div id="display"></div> >+ >+[% MACRO jsinclude BLOCK %] >+ [% INCLUDE 'calendar.inc' %] >+ [% INCLUDE 'datatables.inc' %] >+ [% INCLUDE 'js-date-format.inc' %] >+ [% INCLUDE 'js-biblio-format.inc' %] >+ <script> >+ const authorised_value_categories = [% To.json(AuthorisedValues.GetCategories()) | $raw %].map(c => c.category); >+ const db_columns = [% To.json(db_columns) | $raw %]; >+ const api_mappings = [% To.json(api_mappings) | $raw %]; >+ >+ const csrf_token = "[% Koha.GenerateCSRF | $raw %]"; >+ </script> >+ [% Asset.js("js/vue/dist/display.js") | $raw %] >+[% END %] >+[% INCLUDE 'intranet-bottom.inc' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >index ef569c65ee6..ba32c13c9d4 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/intranet-main.tt >@@ -167,6 +167,12 @@ > </li> > [% END %] > >+ [% IF Koha.Preference('UseDisplayModule') && CAN_user_displays %] >+ <li> >+ <a class="icon_general icon_display" href="/cgi-bin/koha/display/display-home.pl"><i class="fa-solid fa-fw fa-image-portrait"></i>Displays</a> >+ </li> >+ [% END %] >+ > [% IF ( CAN_user_tools || CAN_user_clubs ) %] > <li> > <a class="icon_general icon_tools" href="/cgi-bin/koha/tools/tools-home.pl"><i class="fa fa-fw fa-wrench"></i>Tools</a> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt >index dba569bc1df..35bb025bae0 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/recalls_to_pull.tt >@@ -111,8 +111,8 @@ > </td> > <td class="recall-locations"> > <ul> >- [% FOREACH loc IN recall.locations %] >- <li>[% AuthorisedValues.GetByCode('LOC', loc) | html %]</li> >+ [% FOREACH location IN recall.locations %] >+ <li>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => location ) | html %]</li> > [% END %] > </ul> > </td> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/itemslost.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/itemslost.tt >index 8f87e2161bf..b282f8665d2 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/reports/itemslost.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reports/itemslost.tt >@@ -126,7 +126,7 @@ > <td>[% ItemTypes.GetDescription(item.effective_itemtype) | html %]</td> > <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.ccode', authorised_value => item.ccode ) | html %]</td> > <td>[% Branches.GetName(item.holdingbranch) | html %]</td> >- <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.location ) | html %]</td> >+ <td> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.effective_location ) | html %] </td> > <td>[% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.notforloan', authorised_value => item.notforloan ) | html %] </td><td>[% item.itemnotes | $raw %]</td> > </tr> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tags/list.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tags/list.tt >index 60d1bc4e330..d69a50fb05e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tags/list.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tags/list.tt >@@ -96,7 +96,7 @@ > >[% FOREACH item IN title.items %] > <li> > [% Branches.GetName(item.holdingbranch) | html %] >- <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.location ) | html %] </span> >+ <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.effective_location ) | html %] </span> > [% IF ( item.itemcallnumber ) %] > ([% item.itemcallnumber | html %]) > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >index 42634a034e8..10e354965a4 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >@@ -123,7 +123,7 @@ > [% ELSE %] > <label for="moduleALL" class="viewlog"><input type="checkbox" id="moduleALL" name="modules" value="" /> All</label> > [% END %] >- [% FOREACH modx IN [ 'APIKEYS' 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'CLAIMS' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE', 'NOTICES', 'NEWS', 'RECALLS', 'SUGGESTION', 'TRANSFERS' ] %] >+ [% FOREACH modx IN [ 'APIKEYS' 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'CLAIMS' 'DISPLAYS' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE', 'NOTICES', 'NEWS', 'RECALLS', 'SUGGESTION', 'TRANSFERS' ] %] > [% IF modules.grep(modx).size %] > <label for="module[% modx | html %]" class="viewlog" > ><input type="checkbox" id="module[% modx | html %]" name="modules" value="[% modx | html %]" checked="checked" /> [% PROCESS translate_log_module module=modx %]</label >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/virtualshelves/shelves.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/virtualshelves/shelves.tt >index 65047eb133b..fba74b7112c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/virtualshelves/shelves.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/virtualshelves/shelves.tt >@@ -388,8 +388,8 @@ > [% FOREACH item IN itemsloo.ITEM_RESULTS %] > <li> > [% Branches.GetName(item.holdingbranch) | html %] >- [% IF ( item.location ) %] >- <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.location ) | html %] </span> >+ [% IF ( item.effective_location ) %] >+ <span class="shelvingloc"> [% AuthorisedValues.GetDescriptionByKohaField( kohafield => 'items.location', authorised_value => item.effective_location ) | html %] </span> > [% END %] > [% IF ( item.itemcallnumber ) %] > [<a href="/cgi-bin/koha/catalogue/search.pl?idx=callnum&q=%22[% item.itemcallnumber | uri %]%22">[% item.itemcallnumber | html %]</a>] >diff --git a/koha-tmpl/intranet-tmpl/prog/js/fetch/display-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/fetch/display-api-client.js >index d5490a789c7..e41da83c56b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/fetch/display-api-client.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/fetch/display-api-client.js >@@ -33,14 +33,16 @@ export class DisplayAPIClient { > this.httpClientDisplays.get({ > endpoint: "" + id, > headers: { >- "x-koha-embed": "display_items,home_library,holding_library,item_type,+strings", >+ "x-koha-embed": >+ "display_items,home_library,holding_library,item_type,+strings", > }, > }), > getAll: (query, params) => > this.httpClientDisplays.getAll({ > endpoint: "", > headers: { >- "x-koha-embed": "display_items,home_library,holding_library,+strings", >+ "x-koha-embed": >+ "display_items,home_library,holding_library,+strings", > }, > params, > query, >diff --git a/koha-tmpl/intranet-tmpl/prog/js/fetch/item-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/fetch/item-api-client.js >index f94ff01e8ce..2d87736dc0e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/fetch/item-api-client.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/fetch/item-api-client.js >@@ -20,11 +20,12 @@ export class ItemAPIClient { > }), > getByExternalId: external_id => > this.httpClient.get({ >- endpoint: "items?" + >- new URLSearchParams({ >- _match: 'starts_with', >- external_id: external_id, >- }), >+ endpoint: >+ "items?" + >+ new URLSearchParams({ >+ _match: "starts_with", >+ external_id: external_id, >+ }), > }), > }; > } >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchAddItems.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchAddItems.vue >index a9b62f006fd..b6cf7000e11 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchAddItems.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchAddItems.vue >@@ -3,10 +3,12 @@ > <div class="page-section" id="list"> > <form @submit="batchAdd($event)"> > <fieldset class="rows" id="display_list"> >- <h3>{{ $__("Sepcify items to add") }}:</h3> >+ <h3>{{ $__("Specify items to add") }}:</h3> > <ol> > <li> >- <label for="barcodes">{{ $__("Item barcodes") }}:</label> >+ <label for="barcodes" >+ >{{ $__("Item barcodes") }}:</label >+ > > <textarea > id="barcodes" > v-model="barcodes" >@@ -17,7 +19,8 @@ > /> > <span class="required">{{ $__("Required") }}</span> > <div class="hint"> >- {{ $__("List of item barcodes, one per line") }}<br /> >+ {{ $__("List of item barcodes, one per line") >+ }}<br /> > </div> > </li> > <li> >@@ -58,9 +61,7 @@ > </ol> > </fieldset> > <fieldset class="action"> >- <ButtonSubmit >- :title="$__('Save')" >- /> >+ <ButtonSubmit :title="$__('Save')" /> > <router-link > :to="{ > name: 'DisplaysList', >@@ -104,14 +105,13 @@ export default { > event.preventDefault(); > > barcodes.value = barcodes.value >- .split("\n") >- .map(n => Number(n)) >- .filter(n => { >- if (n == '') >- return false; >+ .split("\n") >+ .map(n => Number(n)) >+ .filter(n => { >+ if (n == "") return false; > >- return true; >- }); >+ return true; >+ }); > > const client = APIClient.display; > const importData = { >@@ -124,15 +124,28 @@ export default { > client.displayItems.batchAdd(importData).then( > success => { > if (success.job_id) >- setMessage(`${$__('Batch job successfully queued.')} <a href="/cgi-bin/koha/admin/background_jobs.pl?op=view&id=${success.job_id}" target="_blank">${$__('Click here to view job progress')}</a>`, true); >+ setMessage( >+ `${$__("Batch job successfully queued.")} <a href="/cgi-bin/koha/admin/background_jobs.pl?op=view&id=${success.job_id}" target="_blank">${$__("Click here to view job progress")}</a>`, >+ true >+ ); > > if (!success.job_id) >- setWarning($__('Batch job failed to queue. Please check your list, and try again.'), true); >+ setWarning( >+ $__( >+ "Batch job failed to queue. Please check your list, and try again." >+ ), >+ true >+ ); > }, > error => { >- setError($__('Internal Server Error. Please check the browser console for diagnostic information.'), true); >+ setError( >+ $__( >+ "Internal Server Error. Please check the browser console for diagnostic information." >+ ), >+ true >+ ); > console.error(error); >- }, >+ } > ); > clearForm(); > }; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchRemoveItems.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchRemoveItems.vue >index 4656eecfa9c..5b4a37d0670 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchRemoveItems.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysBatchRemoveItems.vue >@@ -6,7 +6,9 @@ > <h3>{{ $__("Specify items to remove") }}:</h3> > <ol> > <li> >- <label for="barcodes">{{ $__("Item barcodes") }}:</label> >+ <label for="barcodes" >+ >{{ $__("Item barcodes") }}:</label >+ > > <textarea > id="barcodes" > v-model="barcodes" >@@ -17,7 +19,8 @@ > /> > <span class="required">{{ $__("Required") }}</span> > <div class="hint"> >- {{ $__("List of item barcodes, one per line") }}<br /> >+ {{ $__("List of item barcodes, one per line") >+ }}<br /> > </div> > </li> > <li> >@@ -47,9 +50,7 @@ > </ol> > </fieldset> > <fieldset class="action"> >- <ButtonSubmit >- :title="$__('Save')" >- /> >+ <ButtonSubmit :title="$__('Save')" /> > <router-link > :to="{ > name: 'DisplaysList', >@@ -89,14 +90,13 @@ export default { > event.preventDefault(); > > barcodes.value = barcodes.value >- .split("\n") >- .map(n => Number(n)) >- .filter(n => { >- if (n == '') >- return false; >+ .split("\n") >+ .map(n => Number(n)) >+ .filter(n => { >+ if (n == "") return false; > >- return true; >- }); >+ return true; >+ }); > > const client = APIClient.display; > const importData = { >@@ -106,12 +106,20 @@ export default { > > client.displayItems.batchDelete(importData).then( > success => { >- setMessage(`${$__('Batch job successfully queued.')} <a href="/cgi-bin/koha/admin/background_jobs.pl" target="_blank">${$__('Click here to view job progress')}</a>`, true); >+ setMessage( >+ `${$__("Batch job successfully queued.")} <a href="/cgi-bin/koha/admin/background_jobs.pl" target="_blank">${$__("Click here to view job progress")}</a>`, >+ true >+ ); > }, > error => { >- setError($__('Internal Server Error. Please check the browser console for diagnostic information.'), true); >+ setError( >+ $__( >+ "Internal Server Error. Please check the browser console for diagnostic information." >+ ), >+ true >+ ); > console.error(error); >- }, >+ } > ); > clearForm(); > }; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysResource.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysResource.vue >index 7f2545a775c..245e3e3144c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysResource.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/DisplaysResource.vue >@@ -89,8 +89,7 @@ export default { > name: "display_branch", > label: $__("Home library"), > type: "relationshipSelect", >- relationshipAPIClient: >- APIClient.library.libraries, >+ relationshipAPIClient: APIClient.library.libraries, > relationshipOptionLabelAttr: "name", > relationshipRequiredKey: "library_id", > tableColumnDefinition: { >@@ -100,26 +99,23 @@ export default { > orderable: true, > render: function (data, type, row, meta) { > if (row.home_library === null) >- return (escape_str( >- `` >- )); >+ return escape_str(``); > else >- return (escape_str( >+ return escape_str( > `${row["home_library"]["name"]}` >- )); >+ ); > }, > }, > showElement: { > type: "text", >- value: "home_library.name" >+ value: "home_library.name", > }, > }, > { > name: "display_holding_branch", > label: $__("Holding library"), > type: "relationshipSelect", >- relationshipAPIClient: >- APIClient.library.libraries, >+ relationshipAPIClient: APIClient.library.libraries, > relationshipOptionLabelAttr: "name", > relationshipRequiredKey: "library_id", > tableColumnDefinition: { >@@ -129,18 +125,16 @@ export default { > orderable: true, > render: function (data, type, row, meta) { > if (row.holding_library === null) >- return (escape_str( >- `` >- )); >+ return escape_str(``); > else >- return (escape_str( >+ return escape_str( > `${row["holding_library"]["name"]}` >- )); >+ ); > }, > }, > showElement: { > type: "text", >- value: "holding_library.name" >+ value: "holding_library.name", > }, > }, > { >@@ -159,8 +153,7 @@ export default { > name: "display_itype", > label: $__("Item type"), > type: "relationshipSelect", >- relationshipAPIClient: >- APIClient.item_type.item_types, >+ relationshipAPIClient: APIClient.item_type.item_types, > relationshipOptionLabelAttr: "description", > relationshipRequiredKey: "item_type_id", > tableColumnDefinition: { >@@ -169,19 +162,16 @@ export default { > searchable: true, > orderable: true, > render: function (data, type, row, meta) { >- if (row.item_type === null) >- return (escape_str( >- `` >- )); >+ if (row.item_type === null) return escape_str(``); > else >- return (escape_str( >+ return escape_str( > `${row["item_type"]["description"]}` >- )); >+ ); > }, > }, > showElement: { > type: "text", >- value: "item_type.description" >+ value: "item_type.description", > }, > }, > { >@@ -200,15 +190,16 @@ export default { > searchable: false, > orderable: true, > render: function (data, type, row, meta) { >- let this_value = ''; >+ let this_value = ""; > >- DisplayStore.displayReturnOverMapping.forEach(mapping => { >- if(mapping.variable == data) this_value = mapping.value; >- }); >+ DisplayStore.displayReturnOverMapping.forEach( >+ mapping => { >+ if (mapping.variable == data) >+ this_value = mapping.value; >+ } >+ ); > >- return (escape_str( >- `${this_value}` >- )); >+ return escape_str(`${this_value}`); > }, > }, > }, >@@ -308,9 +299,7 @@ export default { > }, > relationshipI18n: { > nameUpperCase: __("Display item"), >- removeThisMessage: __( >- "Remove this display item" >- ), >+ removeThisMessage: __("Remove this display item"), > addNewMessage: __("Add new display item"), > noneCreatedYetMessage: __( > "There are no display items created yet" >@@ -367,48 +356,51 @@ export default { > actions: { > 0: ["show"], > 1: ["show"], >- "-1": ["edit", "delete"] >+ "-1": ["edit", "delete"], > }, > }; > >- const getItemFromId = (async id => { >+ const getItemFromId = async id => { > const itemsApiClient = APIClient.item.items; > let item = undefined; > >- await itemsApiClient.get(id) >- .then(data => { >- item = data; >- }) >- .catch(error => { >- console.error(error); >- }); >+ await itemsApiClient >+ .get(id) >+ .then(data => { >+ item = data; >+ }) >+ .catch(error => { >+ console.error(error); >+ }); > > return item; >- }); >+ }; > >- const getItemFromExternalId = (async external_id => { >+ const getItemFromExternalId = async external_id => { > const itemsApiClient = APIClient.item.items; > let item = undefined; > >- await itemsApiClient.getByExternalId(external_id) >- .then(data => { >- if (data.length == 1) >- item = data[0]; >- }) >- .catch(error => { >- console.error(error); >- }); >+ await itemsApiClient >+ .getByExternalId(external_id) >+ .then(data => { >+ if (data.length == 1) item = data[0]; >+ }) >+ .catch(error => { >+ console.error(error); >+ }); > > return item; >- }); >+ }; > >- const checkForm = (async display => { >+ const checkForm = async display => { > let errors = []; > > let display_items = display.display_items; > // Do not use di.display_item.name here! Its name is not the one linked with di.display_item_id > // At this point di.display_item is meaningless, form/template only modified di.display_item_id >- const display_item_ids = display_items.map(di => di.display_item_id); >+ const display_item_ids = display_items.map( >+ di => di.display_item_id >+ ); > const duplicate_display_item_ids = display_item_ids.filter( > (id, i) => display_item_ids.indexOf(id) !== i > ); >@@ -419,22 +411,28 @@ export default { > > for await (const display_item of display_items) { > const item = await getItemFromExternalId(display_item.barcode); >- >- if (item == undefined || item.item_id === undefined || item.external_id !== display_item.barcode) >- errors.push($__("The barcode entered does not match an item")); >+ >+ if ( >+ item == undefined || >+ item.item_id === undefined || >+ item.external_id !== display_item.barcode >+ ) >+ errors.push( >+ $__("The barcode entered does not match an item") >+ ); > } > > baseResource.setWarning(errors.join("<br>")); > return !errors.length; >- }); >- const onFormSave = (async (e, displayToSave) => { >+ }; >+ const onFormSave = async (e, displayToSave) => { > e.preventDefault(); > > const display = JSON.parse(JSON.stringify(displayToSave)); > const displayId = display.display_id; > const epoch = new Date(); > >- if (!await checkForm(display)) { >+ if (!(await checkForm(display))) { > return false; > } > >@@ -445,8 +443,7 @@ export default { > delete display._strings; > > display.display_items = display.display_items.map( >- ({ display_item_id, ...keepAttrs }) => >- keepAttrs >+ ({ display_item_id, ...keepAttrs }) => keepAttrs > ); > > let display_items = display.display_items; >@@ -464,10 +461,13 @@ export default { > await display.display_items.push(display_item); > } > >- if (display.start_date == null) display.start_date = epoch.toISOString().substr(0, 10); >+ if (display.start_date == null) >+ display.start_date = epoch.toISOString().substr(0, 10); > if (display.end_date == null && display.display_days != undefined) { > let calculated_date = epoch; >- calculated_date.setDate(epoch.getDate() + Number(display.display_days)); >+ calculated_date.setDate( >+ epoch.getDate() + Number(display.display_days) >+ ); > > display.end_date = calculated_date.toISOString().substr(0, 10); > } >@@ -476,14 +476,12 @@ export default { > if (display.staff_note == "") display.staff_note = null; > > if (displayId) { >- baseResource.apiClient >- .update(display, displayId) >- .then( >- success => { >- baseResource.setMessage($__("Display updated")); >- baseResource.router.push({ name: "DisplaysList" }); >- }, >- error => {} >+ baseResource.apiClient.update(display, displayId).then( >+ success => { >+ baseResource.setMessage($__("Display updated")); >+ baseResource.router.push({ name: "DisplaysList" }); >+ }, >+ error => {} > ); > } else { > baseResource.apiClient.create(display).then( >@@ -494,23 +492,23 @@ export default { > error => {} > ); > } >- }); >- const afterResourceFetch = ((componentData, resource, caller) => { >- if(caller === "show" || caller === "form") { >+ }; >+ const afterResourceFetch = (componentData, resource, caller) => { >+ if (caller === "show" || caller === "form") { > resource.display_items.forEach((display_item, idx) => { > getItemFromId(display_item.itemnumber) >- .then(item => { >- componentData.resource.value.display_items[idx] = { >- barcode: item.external_id, >- ...display_item, >- }; >- }) >- .catch(error => { >- console.error(error); >- }); >+ .then(item => { >+ componentData.resource.value.display_items[idx] = { >+ barcode: item.external_id, >+ ...display_item, >+ }; >+ }) >+ .catch(error => { >+ console.error(error); >+ }); > }); > } >- }); >+ }; > > onBeforeMount(() => {}); > >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/Main.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/Main.vue >index e41ae4b170a..7cd3688dfc7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/Main.vue >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Display/Main.vue >@@ -65,26 +65,24 @@ export default { > } > > DisplayStore.displayReturnOverMapping.push({ >- "variable": "yes - any library", >- "value": $__('Yes, any library'), >+ variable: "yes - any library", >+ value: $__("Yes, any library"), > }); > DisplayStore.displayReturnOverMapping.push({ >- "variable": "yes - except at home library", >- "value": $__('Yes, except at home library'), >+ variable: "yes - except at home library", >+ value: $__("Yes, except at home library"), > }); > DisplayStore.displayReturnOverMapping.push({ >- "variable": "no", >- "value": $__('No'), >- }); >- >- loadAuthorisedValues( >- authorisedValues.value, >- DisplayStore >- ).then(() => { >- loaded(); >- initialized.value = true; >+ variable: "no", >+ value: $__("No"), > }); > >+ loadAuthorisedValues(authorisedValues.value, DisplayStore).then( >+ () => { >+ loaded(); >+ initialized.value = true; >+ } >+ ); > }); > }); > >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js >index 52d258df719..193c519d825 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/api-client.js >@@ -6,10 +6,10 @@ import AcquisitionAPIClient from "@fetch/acquisition-api-client"; > import AdditionalFieldsAPIClient from "@fetch/additional-fields-api-client"; > import AVAPIClient from "@fetch/authorised-values-api-client"; > import CashAPIClient from "@fetch/cash-api-client"; >-import BiblioAPIClient from '@fetch/biblio-api-client.js'; >+import BiblioAPIClient from "@fetch/biblio-api-client.js"; > import DisplayAPIClient from "@fetch/display-api-client"; > import ItemAPIClient from "@fetch/item-api-client"; >-import ItemTypeAPIClient from '@fetch/item-type-api-client.js'; >+import ItemTypeAPIClient from "@fetch/item-type-api-client.js"; > import LibraryAPIClient from "@fetch/library-api-client"; > import RecordSourcesAPIClient from "@fetch/record-sources-api-client"; > import SysprefAPIClient from "@fetch/system-preferences-api-client"; >diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/routes/display.js b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/display.js >index 2e5b882db9f..c8e0674d9d4 100644 >--- a/koha-tmpl/intranet-tmpl/prog/js/vue/routes/display.js >+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/routes/display.js >@@ -62,17 +62,13 @@ export const routes = [ > { > path: "batch-add", > name: "DisplaysBatchAddItems", >- component: markRaw( >- DisplaysBatchAddItems >- ), >+ component: markRaw(DisplaysBatchAddItems), > title: $__("Batch add items from list"), > }, > { > path: "batch-remove", > name: "DisplaysBatchRemoveItems", >- component: markRaw( >- DisplaysBatchRemoveItems >- ), >+ component: markRaw(DisplaysBatchRemoveItems), > title: $__("Batch remove items from list"), > }, > ], >diff --git a/recalls/recalls_to_pull.pl b/recalls/recalls_to_pull.pl >index 0f91a775d1b..026c511657a 100755 >--- a/recalls/recalls_to_pull.pl >+++ b/recalls/recalls_to_pull.pl >@@ -98,7 +98,7 @@ if ( $op eq 'list' ) { > push( @copynumbers, $item->copynumber ) if ( $item->copynumber ); > push( @enumchrons, $item->enumchron ) if ( $item->enumchron ); > push( @itemtypes, $item->effective_itemtype ) if ( $item->effective_itemtype ); >- push( @locations, $item->location ) if ( $item->location ); >+ push( @locations, $item->effective_location ) if ( $item->effective_location ); > push( @libraries, $item->holdingbranch ) if ( $item->holdingbranch ); > } > } >diff --git a/reserve/request.pl b/reserve/request.pl >index fbc08a08269..e71dba414e9 100755 >--- a/reserve/request.pl >+++ b/reserve/request.pl >@@ -458,6 +458,11 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) > my $do_check; > my $item = $item_object->unblessed; > $item->{object} = $item_object; >+ >+ $item->{ccode} = $item_object->effective_collection_code; >+ $item->{holdingbranch} = $item_object->effective_holdingbranch->unblessed; >+ $item->{homebranch} = $item_object->effective_homebranch->unblessed; >+ > if ($patron) { > $do_check = $patron->do_check_for_previous_checkout($item) if $wants_check; > if ( $do_check && $wants_check ) { >-- >2.53.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 14962
:
190216
|
190217
|
190218
|
190219
|
190220
|
190221
|
190222
|
190223
|
190224
|
190225
|
190226
|
190227
|
190228
|
190229
|
190230
|
190231
|
190232
|
190571
|
190572
|
193719
|
193720
|
193721
|
193722
|
193723
|
193724
|
193725
|
193726
|
193727
|
193728
|
193729
|
193730
|
193731
|
193732
|
193733
|
193734
|
193735
|
193736
|
193737
|
193738
|
193739
|
193740
|
193741
|
193742
|
193743
|
193744
|
193745
|
193746
|
193747
|
193748
|
193749
|
193750
|
193751
|
193752
|
193753
|
193754
|
193755
|
194285
|
194286
|
194287
|
194288
|
194289
|
194290
|
194291
|
194292
|
194293
|
194294
|
194295
|
194296
|
194297
|
194298
|
194299
|
194300
|
194301
|
194302
|
194303
|
194304
|
194305
|
194306
|
194307
|
194308
|
194309
|
194310
|
194311
|
194312
|
194313
|
194314
|
194315
|
194316
|
194317
|
194318
|
194320
|
194321
|
194322