From 30edfbfa58c08898242324a2dcfea91a2ab20826 Mon Sep 17 00:00:00 2001 From: ahmed Date: Wed, 21 Jan 2015 14:33:47 -0500 Subject: [PATCH] Bug 10937: Option to hide and group itemtypes from advanced search This allows to group certain item types in a category, to be displayed (and searched) as such in OPAC's advanced search. For example, you can group Reserve 2h and Reserve 12h into a Reserve category. The 2 and 12h types won't appear anymore. This also allows to simply prevent an item type from displaying as a search option. 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. ) Validate returned items are the of the two types that were grouped into the Hardware category in step 4. Sponsored-by: Vanier college Signed-off-by: Nick Signed-off-by: Kyle M Hall Signed-off-by: Tomas Cohen Arazi --- C4/Koha.pm | 59 ++++++++++++++++++- admin/authorised_values.pl | 2 +- admin/itemtypes.pl | 14 ++++- installer/data/mysql/kohastructure.sql | 2 + installer/data/mysql/updatedatabase.pl | 14 +++++ .../prog/en/modules/admin/itemtypes.tt | 32 ++++++++++ .../bootstrap/en/modules/opac-advsearch.tt | 20 ++++++- opac/opac-search.pl | 25 +++++++- t/db_dependent/Koha.t | 46 ++++++++++++++- 9 files changed, 202 insertions(+), 12 deletions(-) diff --git a/C4/Koha.pm b/C4/Koha.pm index bca12d6de2..b1aede70ab 100644 --- a/C4/Koha.pm +++ b/C4/Koha.pm @@ -29,9 +29,9 @@ use Koha::Cache; use Koha::DateUtils qw(dt_from_string); use DateTime::Format::MySQL; use Business::ISBN; -use autouse 'Data::Dumper' => qw(Dumper); +use autouse 'Data::cselectall_arrayref' => qw(Dumper); use DBI qw(:sql_types); - + use Data::Dumper; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG); BEGIN { @@ -43,6 +43,7 @@ BEGIN { &subfield_is_koha_internal_p &GetPrinters &GetPrinter &GetItemTypes &getitemtypeinfo + &GetItemTypesCategorized &GetItemTypesByCategory &GetSupportName &GetSupportList &get_itemtypeinfos_of &getframeworks &getframeworkinfo @@ -274,6 +275,60 @@ sub GetItemTypes { } } +=head2 GetItemTypesCategorized + + $categories = GetItemTypesCategorized(); + +Returns a hashref containing search categories. +A search category will be put in the hash if at least one of its itemtypes is visible in OPAC. +The categories must be part of Authorized Values (DOCTYPECAT) + +=cut + +sub GetItemTypesCategorized { + my $dbh = C4::Context->dbh; + # Order is important, so that partially hidden (some items are not visible in OPAC) search + # categories will be visible. hideinopac=0 must be last. + my $query = q| + 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 + |; +return ($dbh->selectall_hashref($query,'itemtype')); +} + +=head2 GetItemTypesByCategory + + @results = GetItemTypesByCategory( $searchcategory ); + +Returns the itemtype code of all itemtypes included in a searchcategory. + +=cut + +sub GetItemTypesByCategory { + my ($category) = @_; + my $count = 0; + my @results; + my $dbh = C4::Context->dbh; + my $query = qq|SELECT itemtype FROM itemtypes WHERE searchcategory=?|; + my $tmp=$dbh->selectcol_arrayref($query,undef,$category); + return @$tmp; +} + sub get_itemtypeinfos_of { my @itemtypes = @_; diff --git a/admin/authorised_values.pl b/admin/authorised_values.pl index 75343530c8..af6d0e6c3c 100755 --- a/admin/authorised_values.pl +++ b/admin/authorised_values.pl @@ -184,7 +184,7 @@ if ( $op eq 'list' ) { } # 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 3aa9c1d161..1ec15c4717 100755 --- a/admin/itemtypes.pl +++ b/admin/itemtypes.pl @@ -111,6 +111,8 @@ if ( $op eq 'add_form' ) { $remote_image = $data->{imageurl}; } + my $searchcategory = GetAuthorisedValues("DOCTYPECAT", $data->{'searchcategory'}); + $template->param( itemtype => $itemtype, description => $data->{'description'}, @@ -124,6 +126,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 @@ -148,6 +152,8 @@ elsif ( $op eq 'add_validate' ) { , checkinmsg = ? , checkinmsgtype = ? , sip_media_type = ? + , hideinopac = ? + , searchcategory = ? WHERE itemtype = ? '; my $sth = $dbh->prepare($query2); @@ -166,15 +172,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') ); } elsif ( not $already_exists and not $is_a_modif ) { 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'); @@ -190,6 +198,8 @@ elsif ( $op eq 'add_validate' ) { $input->param('checkinmsg'), $input->param('checkinmsgtype'), $sip_media_type, + $input->param('hideinopac') ? 1 : 0, + $input->param('searchcategory'), ); } else { diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 6ae91b835b..e8298e0047 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -1274,6 +1274,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 COLLATE=utf8_unicode_ci; diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 1669c10352..d0c4482083 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -9654,6 +9654,7 @@ if ( CheckVersion($DBversion) ) { SetVersion ($DBversion); } + $DBversion = "3.19.00.003"; if ( CheckVersion($DBversion) ) { my ($count) = $dbh->selectrow_array("SELECT COUNT(*) FROM borrowers GROUP BY userid HAVING COUNT(userid) > 1"); @@ -11143,6 +11144,19 @@ if ( CheckVersion($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.19.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); +} + # DEVELOPER PROCESS, search for anything to execute in the db_update directory # SEE bug 13068 # if there is anything in the atomicupdate, read and execute it. 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 a3d8af4c11..a66317ea54 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt @@ -125,6 +125,25 @@ Item types administration [% END %]
  • Required
  • +
  • + Search category + + (Options are defined as the authorized values for the DOCTYPECAT category) +
  • + [% IF ( noItemTypeImages ) %]
  • Image: Item type images are disabled. To enable them, turn off the noItemTypeImages system preference
  • [% ELSE %] @@ -179,6 +198,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. [% IF ( notforloan ) %] @@ -276,7 +304,9 @@ Item types administration [% UNLESS ( noItemTypeImages ) %]Image[% END %] Code Description + Search category Not for loan + Hide in OPAC Charge Checkin message Actions @@ -290,7 +320,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 a8791a407b..28a1dc0413 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-advsearch.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-advsearch.tt @@ -133,9 +133,25 @@ Limit to any of the following:
      [% FOREACH itemtypeloo IN advsearchloo.code_loop %] -
      + [% IF ((!itemtypeloo.searchcategory) AND (itemtypeloo.cat == 0)) OR (itemtypeloo.cat == 1) %] +
      + + +
      [% IF ( loop.last ) %]
      [% ELSE %][% UNLESS ( loop.count % 4 ) %]
      [% END %][% END %] + [% END %] [% END %]
      diff --git a/opac/opac-search.pl b/opac/opac-search.pl index 81f2bbb4ef..7d21354e3b 100755 --- a/opac/opac-search.pl +++ b/opac/opac-search.pl @@ -84,7 +84,7 @@ 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'); @@ -210,7 +210,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; @@ -244,8 +244,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 ); @@ -263,6 +268,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; @@ -450,6 +456,19 @@ 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'}) { my $multibranch = '('.join( " or ", map { "branch: $_ " } @{ GetBranchesInCategory( $params->{'multibranchlimit'} ) } ).')'; push @limits, $multibranch if ($multibranch ne '()'); diff --git a/t/db_dependent/Koha.t b/t/db_dependent/Koha.t index 2a6850a7cd..84fc5eb2fc 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 => 8; +use Test::More tests => 9; 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'); } @@ -312,4 +313,45 @@ subtest 'GetFrameworksLoop() tests' => sub { ); }; +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', 'Veryheavybook'); + $insertSth->execute('BKghjklo4', 'Another hidden book', 'Veryheavybook', 1); + + my $hrCat = GetItemTypesCategorized(); + ok(exists $hrCat->{Qwertyware}, 'GetItemTypesCategorized: fully visible category exists'); + ok($hrCat->{Veryheavybook} && + $hrCat->{Veryheavybook}->{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', 'Veryheavybook' ); + @results = (); + foreach my $key (@only) { + push @results, $key if exists $hrCat->{$key}; + } + @expected = ( 'BKghjklo1', 'Qwertyware', 'Veryheavybook' ); + is_deeply(\@results,\@expected, 'GetItemTypesCategorized: grouped and ungrouped items returned as expected.'); +}; $dbh->rollback(); -- 2.39.2