From ffb097e07ff006794bfdecef3dc35474ecd7e32c Mon Sep 17 00:00:00 2001 From: Agustin Moyano Date: Tue, 27 Jul 2021 12:20:46 -0300 Subject: [PATCH] Bug 27945: Add limit article request feature Content-Type: text/plain; charset=utf-8 This patch makes it possible to limit article requests per patron per day. To test: 1. Apply patches 2. updatedatabase 3. Enable ArticleRequests preference 4. Edit a patron category and set an article request limit to 1 CHECK => if you set the limit to anything else but a positive number or empty string, a warning appears 5. In staff search biblios and request an article for a patron of the modified category 6. Repeat step 5 SUCCESS => if limit is reached, when you select the user to request an article a warning appears saying that the limit was reached 7. Repeat steps 5 and 6 but this time in opac SUCCESS => Patron is not allowed to request another article if limit is reached 8. prove t/db_dependent/ArticleRequests.t Signed-off-by: Tomas Cohen Arazi Signed-off-by: David Nind Signed-off-by: Marcel de Rooy --- Koha/ArticleRequest.pm | 6 + Koha/Exceptions/ArticleRequest.pm | 47 +++++ Koha/Patron.pm | 26 +++ admin/categories.pl | 190 ++++++++++-------- circ/request-article.pl | 48 +++-- .../prog/en/modules/admin/categories.tt | 20 ++ .../prog/en/modules/circ/request-article.tt | 5 + .../en/modules/opac-request-article.tt | 7 +- opac/opac-request-article.pl | 54 +++-- 9 files changed, 276 insertions(+), 127 deletions(-) create mode 100644 Koha/Exceptions/ArticleRequest.pm mode change 100755 => 100644 admin/categories.pl diff --git a/Koha/ArticleRequest.pm b/Koha/ArticleRequest.pm index 05b0e32542..ac531e8ea4 100644 --- a/Koha/ArticleRequest.pm +++ b/Koha/ArticleRequest.pm @@ -26,6 +26,8 @@ use Koha::Biblios; use Koha::Items; use Koha::Libraries; use Koha::DateUtils qw( dt_from_string ); +use Koha::ArticleRequests; +use Koha::Exceptions::ArticleRequest; use base qw(Koha::Object); @@ -46,6 +48,10 @@ Koha::ArticleRequest - Koha Article Request Object class sub open { my ($self) = @_; + Koha::Exceptions::ArticleRequest::LimitReached->throw( + error => 'Patron cannot request more articles for today' + ) unless $self->borrower->can_request_article; + $self->status(Koha::ArticleRequest::Status::Pending); $self->SUPER::store(); $self->notify(); diff --git a/Koha/Exceptions/ArticleRequest.pm b/Koha/Exceptions/ArticleRequest.pm new file mode 100644 index 0000000000..f9fac5969e --- /dev/null +++ b/Koha/Exceptions/ArticleRequest.pm @@ -0,0 +1,47 @@ +package Koha::Exceptions::ArticleRequest; + +# 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 Exception::Class ( + 'Koha::Exceptions::ArticleRequest' => { + description => 'Something went wrong!', + }, + 'Koha::Exceptions::ArticleRequest::LimitReached' => { + isa => 'Koha::Exceptions::ArticleRequest', + description => 'Article request limit was reached' + }, +); + +=head1 NAME + +Koha::Exceptions::ArticleRequest - Base class for ArticleRequest exceptions + +=head1 Exceptions + +=head2 Koha::Exceptions::ArticleRequest + +Generic ArticleRequest exception + +=head2 Koha::Exceptions::ArticleRequest::IsNotCredit + +Exception to be used when an action on an account line requires it to be a +credit and it isn't. + +=cut + +1; \ No newline at end of file diff --git a/Koha/Patron.pm b/Koha/Patron.pm index 941dace0df..bbdb8d8ff1 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -958,6 +958,32 @@ sub move_to_deleted { return Koha::Database->new->schema->resultset('Deletedborrower')->create($patron_infos); } +=head3 can_request_article + +my $can_request = $borrower->can_request_article + +Returns true if patron can request articles + +=cut + +sub can_request_article { + my ($self) = @_; + my $limit = $self->category->article_request_limit; + + return 1 if !$limit; + + my $date = dt_from_string; + my $count = Koha::ArticleRequests->search({ + borrowernumber => $self->borrowernumber, + status => {'!=' => 'CANCELED'}, + created_on => { + '>=' => $date->date.' 00:00:00', + '<=' => $date->date.' 23:59:59' + } + })->count; + return $count < $limit ? 1 : 0; +} + =head3 article_requests my @requests = $borrower->article_requests(); diff --git a/admin/categories.pl b/admin/categories.pl old mode 100755 new mode 100644 index 368960f9cd..958bfd7c76 --- a/admin/categories.pl +++ b/admin/categories.pl @@ -46,18 +46,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( } ); -if ( $op eq 'add_form' ) { - - $template->param( - category => scalar Koha::Patron::Categories->find($categorycode), - ); - - if ( C4::Context->preference('EnhancedMessagingPreferences') ) { - C4::Form::MessagingPreferences::set_form_values( - { categorycode => $categorycode }, $template ); - } -} -elsif ( $op eq 'add_validate' ) { +if ( $op eq 'add_validate' ) { my $categorycode = $input->param('categorycode'); my $description = $input->param('description'); @@ -78,6 +67,7 @@ elsif ( $op eq 'add_validate' ) { my $exclude_from_local_holds_priority = $input->param('exclude_from_local_holds_priority'); my $min_password_length = $input->param('min_password_length'); my $require_strong_password = $input->param('require_strong_password'); + my $article_request_limit = $input->param('article_request_limit'); my @branches = grep { $_ ne q{} } $input->multi_param('branches'); $reset_password = undef if $reset_password eq -1; @@ -87,88 +77,98 @@ elsif ( $op eq 'add_validate' ) { my $is_a_modif = $input->param("is_a_modif"); - if ($enrolmentperioddate) { - $enrolmentperioddate = output_pref( - { - dt => dt_from_string($enrolmentperioddate), - dateformat => 'iso', - dateonly => 1, - } - ); - } + if ($article_request_limit ne '' && $article_request_limit !~ /\d+/) { + push @messages, {type => 'error', code => 'article_request_numeric_limit' }; + $op = 'add_form'; + } elsif ($article_request_limit ne '' && $article_request_limit < 0) { + push @messages, {type => 'error', code => 'article_request_negative_limit' }; + $op = 'add_form'; + } else { + if ($enrolmentperioddate) { + $enrolmentperioddate = output_pref( + { + dt => dt_from_string($enrolmentperioddate), + dateformat => 'iso', + dateonly => 1, + } + ); + } - if ($is_a_modif) { - my $category = Koha::Patron::Categories->find( $categorycode ); - $category->categorycode($categorycode); - $category->description($description); - $category->enrolmentperiod($enrolmentperiod); - $category->enrolmentperioddate($enrolmentperioddate); - $category->upperagelimit($upperagelimit); - $category->dateofbirthrequired($dateofbirthrequired); - $category->enrolmentfee($enrolmentfee); - $category->reservefee($reservefee); - $category->hidelostitems($hidelostitems); - $category->overduenoticerequired($overduenoticerequired); - $category->category_type($category_type); - $category->BlockExpiredPatronOpacActions($BlockExpiredPatronOpacActions); - $category->checkprevcheckout($checkPrevCheckout); - $category->default_privacy($default_privacy); - $category->reset_password($reset_password); - $category->change_password($change_password); - $category->exclude_from_local_holds_priority($exclude_from_local_holds_priority); - $category->min_password_length($min_password_length); - $category->require_strong_password($require_strong_password); - eval { - $category->store; - $category->replace_library_limits( \@branches ); - }; - if ( $@ ) { - push @messages, {type => 'error', code => 'error_on_update' }; - } else { - push @messages, { type => 'message', code => 'success_on_update' }; + if ($is_a_modif) { + my $category = Koha::Patron::Categories->find( $categorycode ); + $category->categorycode($categorycode); + $category->description($description); + $category->enrolmentperiod($enrolmentperiod); + $category->enrolmentperioddate($enrolmentperioddate); + $category->upperagelimit($upperagelimit); + $category->dateofbirthrequired($dateofbirthrequired); + $category->enrolmentfee($enrolmentfee); + $category->reservefee($reservefee); + $category->hidelostitems($hidelostitems); + $category->overduenoticerequired($overduenoticerequired); + $category->category_type($category_type); + $category->BlockExpiredPatronOpacActions($BlockExpiredPatronOpacActions); + $category->checkprevcheckout($checkPrevCheckout); + $category->default_privacy($default_privacy); + $category->reset_password($reset_password); + $category->change_password($change_password); + $category->exclude_from_local_holds_priority($exclude_from_local_holds_priority); + $category->min_password_length($min_password_length); + $category->require_strong_password($require_strong_password); + $category->article_request_limit($article_request_limit); + eval { + $category->store; + $category->replace_library_limits( \@branches ); + }; + if ( $@ ) { + push @messages, {type => 'error', code => 'error_on_update' }; + } else { + push @messages, { type => 'message', code => 'success_on_update' }; + } } - } - else { - my $category = Koha::Patron::Category->new({ - categorycode => $categorycode, - description => $description, - enrolmentperiod => $enrolmentperiod, - enrolmentperioddate => $enrolmentperioddate, - upperagelimit => $upperagelimit, - dateofbirthrequired => $dateofbirthrequired, - enrolmentfee => $enrolmentfee, - reservefee => $reservefee, - hidelostitems => $hidelostitems, - overduenoticerequired => $overduenoticerequired, - category_type => $category_type, - BlockExpiredPatronOpacActions => $BlockExpiredPatronOpacActions, - checkprevcheckout => $checkPrevCheckout, - default_privacy => $default_privacy, - reset_password => $reset_password, - change_password => $change_password, - exclude_from_local_holds_priority => $exclude_from_local_holds_priority, - min_password_length => $min_password_length, - require_strong_password => $require_strong_password, - }); - eval { - $category->store; - $category->replace_library_limits( \@branches ); - }; - - if ( $@ ) { - push @messages, { type => 'error', code => 'error_on_insert' }; - } else { - push @messages, { type => 'message', code => 'success_on_insert' }; + else { + my $category = Koha::Patron::Category->new({ + categorycode => $categorycode, + description => $description, + enrolmentperiod => $enrolmentperiod, + enrolmentperioddate => $enrolmentperioddate, + upperagelimit => $upperagelimit, + dateofbirthrequired => $dateofbirthrequired, + enrolmentfee => $enrolmentfee, + reservefee => $reservefee, + hidelostitems => $hidelostitems, + overduenoticerequired => $overduenoticerequired, + category_type => $category_type, + BlockExpiredPatronOpacActions => $BlockExpiredPatronOpacActions, + checkprevcheckout => $checkPrevCheckout, + default_privacy => $default_privacy, + reset_password => $reset_password, + change_password => $change_password, + exclude_from_local_holds_priority => $exclude_from_local_holds_priority, + min_password_length => $min_password_length, + require_strong_password => $require_strong_password, + article_request_limit => $article_request_limit + }); + eval { + $category->store; + $category->replace_library_limits( \@branches ); + }; + + if ( $@ ) { + push @messages, { type => 'error', code => 'error_on_insert' }; + } else { + push @messages, { type => 'message', code => 'success_on_insert' }; + } } - } - if ( C4::Context->preference('EnhancedMessagingPreferences') ) { - C4::Form::MessagingPreferences::handle_form_action( $input, - { categorycode => scalar $input->param('categorycode') }, $template ); - } + if ( C4::Context->preference('EnhancedMessagingPreferences') ) { + C4::Form::MessagingPreferences::handle_form_action( $input, + { categorycode => scalar $input->param('categorycode') }, $template ); + } - $searchfield = q||; - $op = 'list'; + $searchfield = q||; + $op = 'list'; + } } elsif ( $op eq 'delete_confirm' ) { @@ -199,6 +199,18 @@ elsif ( $op eq 'delete_confirmed' ) { $op = 'list'; } +if ( $op eq 'add_form' ) { + + $template->param( + category => scalar Koha::Patron::Categories->find($categorycode), + ); + + if ( C4::Context->preference('EnhancedMessagingPreferences') ) { + C4::Form::MessagingPreferences::set_form_values( + { categorycode => $categorycode }, $template ); + } +} + if ( $op eq 'list' ) { my $categories = Koha::Patron::Categories->search( { diff --git a/circ/request-article.pl b/circ/request-article.pl index 678c4c9694..0cc4cc591d 100755 --- a/circ/request-article.pl +++ b/circ/request-article.pl @@ -27,6 +27,7 @@ use C4::Serials qw( CountSubscriptionFromBiblionumber ); use Koha::Biblios; use Koha::Patrons; use Koha::ArticleRequests; +use Try::Tiny; my $cgi = CGI->new; @@ -68,23 +69,29 @@ if ( $action eq 'create' ) { my $patron_notes = $cgi->param('patron_notes') || undef; my $format = $cgi->param('format') || undef; - my $ar = Koha::ArticleRequest->new( - { - borrowernumber => $borrowernumber, - biblionumber => $biblionumber, - branchcode => $branchcode, - itemnumber => $itemnumber, - title => $title, - author => $author, - volume => $volume, - issue => $issue, - date => $date, - pages => $pages, - chapters => $chapters, - patron_notes => $patron_notes, - format => $format, - } - )->store(); + try { + my $ar = Koha::ArticleRequest->new( + { + borrowernumber => $borrowernumber, + biblionumber => $biblionumber, + branchcode => $branchcode, + itemnumber => $itemnumber, + title => $title, + author => $author, + volume => $volume, + issue => $issue, + date => $date, + pages => $pages, + chapters => $chapters, + patron_notes => $patron_notes, + format => $format, + } + )->store(); + } catch { + $template->param( + error_message => $_->{message} + ); + }; } @@ -109,6 +116,13 @@ if ( !$patron && $patron_cardnumber ) { } } +if( $patron && !$patron->can_request_article) { + $patron = undef; + $template->param( + error_message => 'Patron cannot request more articles for today' + ); +} + $template->param( biblio => $biblio, patron => $patron, diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt index 029cc1c28d..5302e1d7b5 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categories.tt @@ -108,6 +108,10 @@ Patron category deleted successfully. [% CASE 'already_exists' %] This patron category already exists. + [% CASE 'article_request_negative_limit' %] + Maximum article request limit cannot be negative. + [% CASE 'article_request_numeric_limit' %] + Maximum article request limit must be a positive number. [% CASE %] [% m.code | html %] [% END %] @@ -202,6 +206,12 @@ + [% IF Koha.Preference('ArticleRequests') %] +
  • + + per day +
  • + [% END %]
  • [% END %] + [% ELSIF error_message %] +

    [% biblio.title | html %]

    +
    + [% error_message | html %] +
    [% ELSE %]

    [% biblio.title | html %]

    diff --git a/opac/opac-request-article.pl b/opac/opac-request-article.pl index dd02b4d7b9..146454f033 100755 --- a/opac/opac-request-article.pl +++ b/opac/opac-request-article.pl @@ -26,6 +26,7 @@ use C4::Output qw( output_html_with_http_headers ); use Koha::Biblios; use Koha::Patrons; +use Try::Tiny; my $cgi = CGI->new; @@ -59,26 +60,33 @@ if ( $action eq 'create' ) { my $patron_notes = $cgi->param('patron_notes') || undef; my $format = $cgi->param('format') || undef; - my $ar = Koha::ArticleRequest->new( - { - borrowernumber => $borrowernumber, - biblionumber => $biblionumber, - branchcode => $branchcode, - itemnumber => $itemnumber, - title => $title, - author => $author, - volume => $volume, - issue => $issue, - date => $date, - pages => $pages, - chapters => $chapters, - patron_notes => $patron_notes, - format => $format, - } - )->store(); - - print $cgi->redirect("/cgi-bin/koha/opac-user.pl#opac-user-article-requests"); - exit; + try { + my $ar = Koha::ArticleRequest->new( + { + borrowernumber => $borrowernumber, + biblionumber => $biblionumber, + branchcode => $branchcode, + itemnumber => $itemnumber, + title => $title, + author => $author, + volume => $volume, + issue => $issue, + date => $date, + pages => $pages, + chapters => $chapters, + patron_notes => $patron_notes, + format => $format, + } + )->store(); + + print $cgi->redirect("/cgi-bin/koha/opac-user.pl#opac-user-article-requests"); + exit; + } catch { + exit unless $_->[0] && $_->[0] eq 'EXIT'; + $template->param( + error_message => $_->{message} + ); + }; # Should we redirect? } elsif ( !$action && C4::Context->preference('ArticleRequestsOpacHostRedirection') ) { @@ -96,6 +104,12 @@ elsif ( !$action && C4::Context->preference('ArticleRequestsOpacHostRedirection' my $patron = Koha::Patrons->find($borrowernumber); +if(!$patron->can_request_article) { + $template->param( + error_message => 'You cannot request more articles for today' + ); +} + $template->param( biblio => $biblio, patron => $patron, -- 2.20.1