diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index 833b9bbb80..832dddd3f9 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -2154,6 +2154,51 @@ sub link_marc_host { return $self; } +=head3 age_restriction + + my $age = $biblio->age_restriction; + +Extracts the numeric age restriction from the biblio's agerestriction field +using the AgeRestrictionMarker system preference. + +Returns the age (integer) or undef if no restriction is found. + +=cut + +sub age_restriction { + my ($self) = @_; + + my $restriction_string = $self->biblioitem->agerestriction; + return unless $restriction_string; + + my @values = split ' ', uc($restriction_string); + return unless @values; + + my @markers = map { my $m = uc($_); $m =~ s/^\s+//; $m =~ s/\s+$//; $m } + @{ C4::Context->multivalue_preference('AgeRestrictionMarker') }; + return unless @markers; + + my $index = 0; + my $restriction_age = 0; + for my $value (@values) { + $index++; + for my $marker (@markers) { + if ( $marker eq $value ) { + if ( $index <= $#values ) { + $restriction_age += $values[$index]; + } + last; + } elsif ( $value =~ /^\Q$marker\E(\d+)$/ ) { + $restriction_age += $1; + last; + } + } + last if ( $restriction_age > 0 ); + } + + return $restriction_age || undef; +} + =head3 recalls my $recalls = $biblio->recalls; diff --git a/Koha/Policy/Biblio/AgeRestriction.pm b/Koha/Policy/Biblio/AgeRestriction.pm new file mode 100644 index 0000000000..676e4ebc27 --- /dev/null +++ b/Koha/Policy/Biblio/AgeRestriction.pm @@ -0,0 +1,57 @@ +package Koha::Policy::Biblio::AgeRestriction; + +# Copyright 2026 Theke Solutions +# +# 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 . + +use Modern::Perl; + +use Koha::Result::Boolean; + +=head1 NAME + +Koha::Policy::Biblio::AgeRestriction - age restriction policy checks + +=head1 API + +=head2 Class methods + +=head3 check + + my $result = Koha::Policy::Biblio::AgeRestriction->check( $biblio, $patron ); + +Checks whether a patron meets the age restriction for a biblio. + +Returns undef if there is no restriction or it cannot be evaluated +(e.g. patron has no date of birth). Otherwise returns a L: +true if the patron meets the restriction, false (with message) if not. + +=cut + +sub check { + my ( $class, $biblio, $patron ) = @_; + + my $restriction_age = $biblio->age_restriction; + return Koha::Result::Boolean->new(1) unless $restriction_age; + return Koha::Result::Boolean->new(1) unless $patron->dateofbirth; + + return $restriction_age > $patron->get_age + ? Koha::Result::Boolean->new(0) + ->add_message( { message => 'age_restricted', payload => { restriction_age => $restriction_age } } ) + : Koha::Result::Boolean->new(1); +} + +1; diff --git a/t/db_dependent/Koha/Policy/Biblio/AgeRestriction.t b/t/db_dependent/Koha/Policy/Biblio/AgeRestriction.t new file mode 100755 index 0000000000..04021bc21d --- /dev/null +++ b/t/db_dependent/Koha/Policy/Biblio/AgeRestriction.t @@ -0,0 +1,101 @@ +#!/usr/bin/env perl + +# This file is part of Koha. +# +# Copyright 2015 Koha Development Team +# Copyright 2026 Theke Solutions +# +# 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 . + +use Modern::Perl; + +use Test::More tests => 3; +use Test::NoWarnings; + +use t::lib::Mocks; +use t::lib::TestBuilder; + +use Koha::Database; +use Koha::Policy::Biblio::AgeRestriction; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +t::lib::Mocks::mock_preference( 'AgeRestrictionMarker', 'FSK|PEGI|Age|K' ); + +subtest 'Koha::Biblio->age_restriction' => sub { + plan tests => 7; + + $schema->storage->txn_begin; + + my $biblio_fsk = $builder->build_sample_biblio; + $biblio_fsk->biblioitem->agerestriction('FSK 16')->store; + is( $biblio_fsk->age_restriction, 16, 'FSK 16 returns 16' ); + + my $biblio_pegi = $builder->build_sample_biblio; + $biblio_pegi->biblioitem->agerestriction('PEGI 16')->store; + is( $biblio_pegi->age_restriction, 16, 'PEGI 16 returns 16' ); + + my $biblio_pegi_no_space = $builder->build_sample_biblio; + $biblio_pegi_no_space->biblioitem->agerestriction('PEGI16')->store; + is( $biblio_pegi_no_space->age_restriction, 16, 'PEGI16 returns 16' ); + + my $biblio_age = $builder->build_sample_biblio; + $biblio_age->biblioitem->agerestriction('Age 16')->store; + is( $biblio_age->age_restriction, 16, 'Age 16 returns 16' ); + + my $biblio_k = $builder->build_sample_biblio; + $biblio_k->biblioitem->agerestriction('K16')->store; + is( $biblio_k->age_restriction, 16, 'K16 returns 16' ); + + my $biblio_none = $builder->build_sample_biblio; + $biblio_none->biblioitem->agerestriction(undef)->store; + is( $biblio_none->age_restriction, undef, 'No restriction returns undef' ); + + my $biblio_empty = $builder->build_sample_biblio; + $biblio_empty->biblioitem->agerestriction('')->store; + is( $biblio_empty->age_restriction, undef, 'Empty restriction returns undef' ); + + $schema->storage->txn_rollback; +}; + +subtest 'Koha::Policy::Biblio::AgeRestriction->check' => sub { + plan tests => 6; + + $schema->storage->txn_begin; + + my $biblio = $builder->build_sample_biblio; + $biblio->biblioitem->agerestriction('FSK 16')->store; + + my $young_patron = $builder->build_object( { class => 'Koha::Patrons', value => { dateofbirth => '2016-01-01' } } ); + my $adult_patron = $builder->build_object( { class => 'Koha::Patrons', value => { dateofbirth => '1990-01-01' } } ); + my $no_dob_patron = $builder->build_object( { class => 'Koha::Patrons', value => { dateofbirth => undef } } ); + + my $result = Koha::Policy::Biblio::AgeRestriction->check( $biblio, $young_patron ); + ok( defined $result && !$result, 'Young patron is restricted' ); + is( $result->messages->[0]->message, 'age_restricted', 'Message is age_restricted' ); + is( $result->messages->[0]->payload->{restriction_age}, 16, 'Restriction age in message payload' ); + + $result = Koha::Policy::Biblio::AgeRestriction->check( $biblio, $adult_patron ); + ok( $result, 'Adult patron is not restricted' ); + + $result = Koha::Policy::Biblio::AgeRestriction->check( $biblio, $no_dob_patron ); + ok( $result, 'No date of birth returns true (permissive)' ); + + my $biblio_no_restriction = $builder->build_sample_biblio; + $result = Koha::Policy::Biblio::AgeRestriction->check( $biblio_no_restriction, $young_patron ); + ok( $result, 'No restriction returns true (permissive)' ); + + $schema->storage->txn_rollback; +};