@@ -, +, @@ search ------------------ -- all tests should pass. two columns to itemtypes -- Does a meaningful message get printed? Are the columns added? "DESCRIBE itemtypes;" should list hideinopac and searchcategory. a) In Intranet/Koha Admin/Authorized values, select DOCTYPECAT in the 'Show category:' dropdown i) If you do not have a DOCTYPECAT category, create one. b) Click button "New authorized value for DOCTYPECAT" c) Enter Authorized value: HARDWARE Description : Hardware Description (OPAC): Hardware a) In Intranet/Koha Admin/Item types, choose (at least) two item types and for each: - Click action/Edit on the right column - Third row (below Description) is the Search category list box, select Hardware - click Save changes at the bottom a) In Intranet/Koha Admin/Item types (again), choose a different item type: - Click action/Edit - Click the checkbox "Hide in OPAC" below the list of icons. a) Go to OPAC/Adv search. b) Validate that all items modified above (hidden or grouped) do not appear in Item type list c) Validate that new item type Hardware does appear instead. d) Select item Hardware, start Search. e) Validate returned items are the of the two types that were grouped into the Hardware category in step 4. --- C4/Koha.pm | 64 ++++++++++++++++++++ admin/authorised_values.pl | 2 +- admin/itemtypes.pl | 14 ++++- installer/data/mysql/kohastructure.sql | 2 + installer/data/mysql/updatedatabase.pl | 13 ++++ .../prog/en/modules/admin/itemtypes.tt | 46 ++++++++++++++ .../bootstrap/en/modules/opac-advsearch.tt | 4 +- .../opac-tmpl/prog/en/modules/opac-advsearch.tt | 6 +- opac/opac-search.pl | 28 +++++++-- t/db_dependent/Koha.t | 47 +++++++++++++- 10 files changed, 213 insertions(+), 13 deletions(-) --- a/C4/Koha.pm +++ a/C4/Koha.pm @@ -43,6 +43,7 @@ BEGIN { &subfield_is_koha_internal_p &GetPrinters &GetPrinter &GetItemTypes &getitemtypeinfo + &GetItemTypesCategorized &GetItemTypesByCategory &GetSupportName &GetSupportList &get_itemtypeinfos_of &getframeworks &getframeworkinfo @@ -275,6 +276,69 @@ sub GetItemTypes { } } +=head2 GetItemTypesCategorized + +Returns item types but grouped by category if available. +The categories must be part of Authorized Values (DOCTYPECAT) + +=cut + +sub GetItemTypesCategorized { + my $dbh = C4::Context->dbh; + # Order is important, so that partially hidden search + # categories will be visible. hideinopac=0 must be last. + my $query = qq| + SELECT itemtype, description, imageurl, hideinopac, 0 as 'iscat' FROM itemtypes WHERE ISNULL(searchcategory) or length(searchcategory) = 0 + UNION + SELECT DISTINCT searchcategory AS `itemtype`, + authorised_values.lib_opac AS description, + authorised_values.imageurl AS imageurl, + hideinopac, 1 as 'iscat' + FROM itemtypes + LEFT JOIN authorised_values ON searchcategory = authorised_value + WHERE searchcategory > '' and hideinopac=1 + UNION + SELECT DISTINCT searchcategory AS `itemtype`, + authorised_values.lib_opac AS description, + authorised_values.imageurl AS imageurl, + hideinopac, 1 as 'iscat' + FROM itemtypes + LEFT JOIN authorised_values ON searchcategory = authorised_value + WHERE searchcategory > '' and hideinopac=0 + |; + my $sth = $dbh->prepare($query); + $sth->execute; + + my %itemtypes; + while ( my $IT = $sth->fetchrow_hashref ) { + $itemtypes{ $IT->{'itemtype'} } = $IT; + } + + return ( \%itemtypes ); +} + +=head2 GetItemTypesByCategory + + $category = category filter + +Returns the itemtypes that are grouped into the category. + +=cut + +sub GetItemTypesByCategory { + my ($category) = @_; + my $count = 0; + my @results; + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare("SELECT itemtype FROM itemtypes WHERE searchcategory=?"); + $sth->execute($category); + + while ( my $data = $sth->fetchrow ) { + push ( @results, $data ); + } + return @results; +} + sub get_itemtypeinfos_of { my @itemtypes = @_; --- a/admin/authorised_values.pl +++ a/admin/authorised_values.pl @@ -247,7 +247,7 @@ sub default_form { } # push koha system categories - foreach (qw(Asort1 Asort2 Bsort1 Bsort2 SUGGEST DAMAGED LOST REPORT_GROUP REPORT_SUBGROUP DEPARTMENT TERM SUGGEST_STATUS)) { + foreach (qw(Asort1 Asort2 Bsort1 Bsort2 SUGGEST DAMAGED LOST REPORT_GROUP REPORT_SUBGROUP DEPARTMENT TERM SUGGEST_STATUS DOCTYPECAT)) { push @category_list, $_ unless $categories{$_}; } --- a/admin/itemtypes.pl +++ a/admin/itemtypes.pl @@ -112,6 +112,8 @@ if ( $op eq 'add_form' ) { $remote_image = $data->{imageurl}; } + my $searchcategory = GetAuthorisedValues("DOCTYPECAT", $data->{'searchcategory'}); + $template->param( itemtype => $itemtype, description => $data->{'description'}, @@ -125,6 +127,8 @@ if ( $op eq 'add_form' ) { imagesets => $imagesets, remote_image => $remote_image, sip_media_type => $data->{sip_media_type}, + hideinopac => $data->{'hideinopac'}, + searchcategory => $searchcategory, ); # END $OP eq ADD_FORM @@ -150,6 +154,8 @@ elsif ( $op eq 'add_validate' ) { , checkinmsg = ? , checkinmsgtype = ? , sip_media_type = ? + , hideinopac = ? + , searchcategory = ? WHERE itemtype = ? '; $sth = $dbh->prepare($query2); @@ -168,15 +174,17 @@ elsif ( $op eq 'add_validate' ) { $input->param('checkinmsg'), $input->param('checkinmsgtype'), $sip_media_type, + $input->param('hideinopac') ? 1 : 0, + $input->param('searchcategory'), $input->param('itemtype') ); } else { # add a new itemtype & not modif an old my $query = " INSERT INTO itemtypes - (itemtype,description,rentalcharge, notforloan, imageurl, summary, checkinmsg, checkinmsgtype, sip_media_type) + (itemtype,description,rentalcharge, notforloan, imageurl, summary, checkinmsg, checkinmsgtype, sip_media_type, hideinopac, searchcategory) VALUES - (?,?,?,?,?,?,?,?,?); + (?,?,?,?,?,?,?,?,?,?,?); "; my $sth = $dbh->prepare($query); my $image = $input->param('image'); @@ -192,6 +200,8 @@ elsif ( $op eq 'add_validate' ) { $input->param('checkinmsg'), $input->param('checkinmsgtype'), $sip_media_type, + $input->param('hideinopac') ? 1 : 0, + $input->param('searchcategory'), ); } --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -1247,6 +1247,8 @@ CREATE TABLE `itemtypes` ( -- defines the item types checkinmsg VARCHAR(255), -- message that is displayed when an item with the given item type is checked in checkinmsgtype CHAR(16) DEFAULT 'message' NOT NULL, -- type (CSS class) for the checkinmsg, can be "alert" or "message" sip_media_type VARCHAR(3) DEFAULT NULL, -- SIP2 protocol media type for this itemtype + hideinopac tinyint(1) NOT NULL DEFAULT 0, -- Hide the item type from the search options in OPAC + searchcategory varchar(20) default NULL, -- Group this item type with others with the same value on OPAC search options PRIMARY KEY (`itemtype`), UNIQUE KEY `itemtype` (`itemtype`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -8551,6 +8551,19 @@ if (CheckVersion($DBversion)) { SetVersion($DBversion); } +$DBversion = "3.17.00.XXX"; +if ( CheckVersion($DBversion) ) { + $dbh->do(q{ + ALTER TABLE itemtypes + ADD hideinopac TINYINT(1) NOT NULL DEFAULT 0 + AFTER sip_media_type, + ADD searchcategory VARCHAR(20) DEFAULT NULL + AFTER hideinopac; + }); + print "Upgrade to $DBversion done (Bug 10937 - Option to hide and group itemtypes from advanced search)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt @@ -109,6 +109,39 @@ Item types administration [% END %]
  • Required
  • + [% IF ( itemtype ) %] +
  • + Search category + + (Options are defined as the authorized values for the DOCTYPECAT category) +
  • + [% ELSE %] +
  • + Search category + +
  • + [% END %] + [% IF ( noItemTypeImages ) %]
  • Image: Item type images are disabled. To enable them, turn off the noItemTypeImages system preference
  • [% ELSE %] @@ -164,6 +197,15 @@ Item types administration [% END %]
    1. + + [% IF ( hideinopac ) %] + + [% ELSE %] + + [% END %] + (if checked, items of this type will be hidden as filters in OPAC's advanced search) +
    2. +
    3. [% IF ( notforloan ) %] [% ELSE %] @@ -260,7 +302,9 @@ Item types administration [% UNLESS ( noItemTypeImages ) %]Image[% END %] Code Description + Search category Not for loan + Hide in OPAC Charge Checkin message Actions @@ -278,7 +322,9 @@ Item types administration [% loo.description %] + [% loo.searchcategory %] [% IF ( loo.notforloan ) %]Yes[% ELSE %] [% END %] + [% IF ( loo.hideinopac ) %]Yes[% ELSE %] [% END %] [% UNLESS ( loo.notforloan ) %] [% loo.rentalcharge %] --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-advsearch.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-advsearch.tt @@ -141,9 +141,11 @@ Limit to any of the following:
      [% FOREACH itemtypeloo IN advsearchloo.code_loop %] -
      [% ELSE %][% UNLESS ( loop.count % 4 ) %]
      [% END %][% END %] + [% END %] [% END %]
      --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt +++ a/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt @@ -187,8 +187,10 @@ [% FOREACH itemtypeloo IN advsearchloo.code_loop %] - + [% IF ((!itemtypeloo.searchcategory) AND (itemtypeloo.cat == 0)) OR (itemtypeloo.cat == 1) %] + + [% END %] [% IF ( loop.last ) %][% ELSE %][% UNLESS ( loop.count % 5 ) %][% END %][% END %] [% END %]
      --- a/opac/opac-search.pl +++ a/opac/opac-search.pl @@ -95,17 +95,17 @@ my ($template,$borrowernumber,$cookie); my $template_name; my $template_type = 'basic'; my @params = $cgi->param("limit"); - +my @searchCategories = $cgi->param('searchcat'); my $format = $cgi->param("format") || ''; my $build_grouped_results = C4::Context->preference('OPACGroupResults'); if ($format =~ /(rss|atom|opensearchdescription)/) { $template_name = 'opac-opensearch.tmpl'; } -elsif (@params && $build_grouped_results) { +elsif ((@params || @searchCategories) && $build_grouped_results) { $template_name = 'opac-results-grouped.tmpl'; } -elsif ((@params>=1) || ($cgi->param("q")) || ($cgi->param('multibranchlimit')) || ($cgi->param('limit-yr')) ) { +elsif (((@params>=1) || (@searchCategories>=1)) || ($cgi->param("q")) || ($cgi->param('multibranchlimit')) || ($cgi->param('limit-yr')) ) { $template_name = 'opac-results.tmpl'; } else { @@ -205,7 +205,7 @@ my $languages_limit_loop = getLanguages($lang, 1); $template->param(search_languages_loop => $languages_limit_loop,); # load the Type stuff -my $itemtypes = GetItemTypes; +my $itemtypes = GetItemTypesCategorized; # the index parameter is different for item-level itemtypes my $itype_or_itemtype = (C4::Context->preference("item-level_itypes"))?'itype':'itemtype'; my @advancedsearchesloop; @@ -223,8 +223,13 @@ foreach my $advanced_srch_type (@advanced_search_types) { code => $thisitemtype, description => $itemtypes->{$thisitemtype}->{'description'}, imageurl=> getitemtypeimagelocation( 'opac', $itemtypes->{$thisitemtype}->{'imageurl'} ), + cat => $itemtypes->{$thisitemtype}->{'iscat'}, + hideinopac => $itemtypes->{$thisitemtype}->{'hideinopac'}, + searchcategory => $itemtypes->{$thisitemtype}->{'searchcategory'}, ); - push @itypesloop, \%row; + if ( !$itemtypes->{$thisitemtype}->{'hideinopac'} ) { + push @itypesloop, \%row; + } } my %search_code = ( advanced_search_type => $advanced_srch_type, code_loop => \@itypesloop ); @@ -239,6 +244,7 @@ foreach my $advanced_srch_type (@advanced_search_types) { ccl => $advanced_srch_type, code => $thisitemtype->{authorised_value}, description => $thisitemtype->{'lib_opac'} || $thisitemtype->{'lib'}, + searchcategory => $itemtypes->{$thisitemtype}->{'searchcategory'}, imageurl => getitemtypeimagelocation( 'opac', $thisitemtype->{'imageurl'} ), ); push @authvalueloop, \%row; @@ -406,6 +412,18 @@ my @limits = $cgi->param('limit'); my @nolimits = $cgi->param('nolimit'); my %is_nolimit = map { $_ => 1 } @nolimits; @limits = grep { not $is_nolimit{$_} } @limits; + +if (@searchCategories > 0) { + my @tabcat; + foreach my $typecategory (@searchCategories) { + push (@tabcat, GetItemTypesByCategory($typecategory)); + } + + foreach my $itemtypeInCategory (@tabcat) { + push (@limits, "mc-$itype_or_itemtype,phr:".$itemtypeInCategory); + } +} + @limits = map { uri_unescape($_) } @limits; if($params->{'multibranchlimit'}) { --- a/t/db_dependent/Koha.t +++ a/t/db_dependent/Koha.t @@ -7,12 +7,13 @@ use strict; use warnings; use C4::Context; use Koha::DateUtils qw(dt_from_string); +use Data::Dumper; -use Test::More tests => 7; +use Test::More tests => 8; use DateTime::Format::MySQL; BEGIN { - use_ok('C4::Koha', qw( :DEFAULT GetDailyQuote )); + use_ok('C4::Koha', qw( :DEFAULT GetDailyQuote GetItemTypesByCategory GetItemTypesCategorized)); use_ok('C4::Members'); } @@ -261,3 +262,45 @@ subtest 'getFacets() tests' => sub { 'location facet present with singleBranchMode on (bug 10078)' ); }; + +subtest 'GetItemTypesByCategory GetItemTypesCategorized test' => sub{ + plan tests => 7; + + my $insertGroup = AddAuthorisedValue('DOCTYPECAT', 'Qwertyware'); + ok($insertGroup, "Create group Qwertyware"); + + my $query = "INSERT into itemtypes (itemtype, description, searchcategory, hideinopac) values (?,?,?,?)"; + my $insertSth = C4::Context->dbh->prepare($query); + $insertSth->execute('BKghjklo1', 'One type of book', '', 0); + $insertSth->execute('BKghjklo2', 'Another type of book', 'Qwertyware', 0); + $insertSth->execute('BKghjklo3', 'Yet another type of book', 'Qwertyware', 0); + + # Azertyware should not exist. + my @results = GetItemTypesByCategory('Azertyware'); + is(scalar @results, 0, 'GetItemTypesByCategory: Invalid category returns nothing'); + + @results = GetItemTypesByCategory('Qwertyware'); + my @expected = ( 'BKghjklo2', 'BKghjklo3' ); + is_deeply(\@results,\@expected,'GetItemTypesByCategory: valid category returns itemtypes'); + + # add more data since GetItemTypesCategorized's search is more subtle + $insertGroup = AddAuthorisedValue('DOCTYPECAT', 'Veryveryheavybook'); + $insertSth->execute('BKghjklo4', 'Another hidden book', 'Veryveryheavybook', 1); + + my $hrCat = GetItemTypesCategorized(); + ok(exists $hrCat->{Qwertyware}, 'GetItemTypesCategorized: fully visible category exists'); + ok($hrCat->{Veryveryheavybook} && + $hrCat->{Veryveryheavybook}->{hideinopac}==1, 'GetItemTypesCategorized: non-visible category hidden' ); + + $insertSth->execute('BKghjklo5', 'An hidden book', 'Qwertyware', 1); + $hrCat = GetItemTypesCategorized(); + ok(exists $hrCat->{Qwertyware}, 'GetItemTypesCategorized: partially visible category exists'); + + my @only = ( 'BKghjklo1', 'BKghjklo2', 'BKghjklo3', 'BKghjklo4', 'BKghjklo5', 'Qwertyware', 'Veryveryheavybook' ); + @results = (); + foreach my $key (@only) { + push @results, $key if exists $hrCat->{$key}; + } + @expected = ( 'BKghjklo1', 'Qwertyware', 'Veryveryheavybook' ); + is_deeply(\@results,\@expected, 'GetItemTypesCategorized: grouped and ungrouped items returned as expected.'); +} --