From a45da698cd6d825c6aed2a69825a4a95ff110eef Mon Sep 17 00:00:00 2001 From: Blou Date: Mon, 27 Jan 2014 13:16:05 -0500 Subject: [PATCH] Bug 10937 - Option to hide and group itemtypes from advanced search It's possible to hide the records and the items, but the advanced search form is a bit trickier. It would be nice if we could specify which itemtypes are offered as search options in the OPAC advanced search form. To solve this, two new columns will be added in the item type. 1) Display in OPAC Default : Yes Set to NO to hide and itemtype in the opac's advanced search. 2) Search category The search category allows library to group some similar itemtypes in a single checkbox in the opac. The categories are defined in an Authorized value. For Example, itemtypes DVD, VHS could use the Video category. Searching for Video in the OPAC would returns the DVD and VHS items. As C4/Koha was modified, a set of subtests were added to confirm the changes in t/db_dependent/Koha.t. The two new routines add a grouping functionality into the OPAC Advanced Search Item type display area. Initial coding by philippe.blouin@inlibro.com with mtompset@hotmail.com providing extra testing, patching, squashing, and rebasing. CURRENT TEST PLAN ------------------ 0) Back up database, so you can reset and retest easily. ;) 1) Apply the patch 2) Run Koha QA tool. 3) prove -v t/db_dependent/Koha.t -- all tests should pass. 4) run ./installer/data/mysql/updatedatabase.pl to add the two columns to itemtypes -- Does a meaningful message get printed? Are the columns added? "DESCRIBE itemtypes;" should list hideinopac and searchcategory. 5) You need to add a category to group your item types: 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 6) Group your items under that new category 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 7) Select at least one item to be hidden in the OPAC search 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. 8) Go test your modifications 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. Sponsored-by: Vanier college --- 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(-) diff --git a/C4/Koha.pm b/C4/Koha.pm index 6f98ac6..f577907 100644 --- a/C4/Koha.pm +++ b/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 = @_; diff --git a/admin/authorised_values.pl b/admin/authorised_values.pl index 332f09a..47847f9 100755 --- a/admin/authorised_values.pl +++ b/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{$_}; } diff --git a/admin/itemtypes.pl b/admin/itemtypes.pl index 87af801..c8ec47c 100755 --- a/admin/itemtypes.pl +++ b/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'), ); } diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index b46dc6a..0f08f4c 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/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; diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 01472d7..97253c1 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/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) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt index 522420b..2467902 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt +++ b/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 %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-advsearch.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-advsearch.tt index d9b2d4b..f4f9fe0 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-advsearch.tt +++ b/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 %]
      diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt index 04ab78c..8bf2dc0 100644 --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt +++ b/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 %]
      diff --git a/opac/opac-search.pl b/opac/opac-search.pl index 990cbd0..2a58366 100755 --- a/opac/opac-search.pl +++ b/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'}) { diff --git a/t/db_dependent/Koha.t b/t/db_dependent/Koha.t index 0e90403..85df0cd 100644 --- a/t/db_dependent/Koha.t +++ b/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.'); +} -- 1.7.9.5