From 8595e80b7858c7eeb7b11a1dd33f338fce12791c Mon Sep 17 00:00:00 2001 From: Andrew Isherwood Date: Fri, 22 Nov 2019 11:08:53 +0000 Subject: [PATCH] Bug 24083: Add support for unseen_renewals This patch adds support for unseen renewals. Here we retrofit knowledge of unseen renewals and add the display of unseen renewal counts and warnings, in addition to adding the ability to specify a renewal as being "unseen". The functionality added here is goverened by the UnseenRenewals syspref. Signed-off-by: Sally Healey Signed-off-by: Katrin Fischer Signed-off-by: Jonathan Druart --- C4/Circulation.pm | 172 +++++++++++++++++- C4/ILSDI/Services.pm | 2 +- C4/SIP/ILS/Transaction/Renew.pm | 1 + Koha/CirculationRules.pm | 3 + Koha/REST/V1/Checkouts.pm | 11 +- api/v1/swagger/definitions/checkout.json | 4 + api/v1/swagger/parameters.json | 3 + api/v1/swagger/parameters/checkout.json | 7 + api/v1/swagger/paths/checkouts.json | 7 +- circ/renew.pl | 11 +- .../prog/css/src/staff-global.scss | 12 ++ .../prog/en/includes/checkouts-table.inc | 4 + .../prog/en/modules/circ/circulation.tt | 1 + .../prog/en/modules/circ/renew.tt | 38 +++- .../prog/en/modules/members/moremember.tt | 1 + koha-tmpl/intranet-tmpl/prog/js/checkouts.js | 24 ++- .../bootstrap/en/modules/opac-user.tt | 44 ++++- misc/cronjobs/automatic_renewals.pl | 2 +- offline_circ/download.pl | 1 + opac/opac-renew.pl | 2 +- opac/opac-user.pl | 10 +- svc/checkouts | 12 +- svc/renew | 3 +- 23 files changed, 340 insertions(+), 35 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index b33e6d58d1..6acab2713a 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -2773,6 +2773,7 @@ sub CanBookBeRenewed { 'no_auto_renewal_after_hard_limit', 'lengthunit', 'norenewalbefore', + 'unseen_renewals_allowed' ] } ); @@ -2951,12 +2952,124 @@ sub CanBookBeRenewed { return ( 0, "auto_renew" ) if $auto_renew eq "ok" && !$override_limit; # 0 if auto-renewal should not succeed + return ( 1, undef ) if $override_limit; + + my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed ); + my $issuing_rule = Koha::CirculationRules->get_effective_rules( + { + categorycode => $patron->categorycode, + itemtype => $item->effective_itemtype, + branchcode => $branchcode, + rules => [ + 'renewalsallowed', + 'no_auto_renewal_after', + 'no_auto_renewal_after_hard_limit', + 'lengthunit', + 'norenewalbefore', + 'unseen_renewals_allowed' + ] + } + ); + + return ( 0, "too_many" ) + if not $issuing_rule->{renewalsallowed} or $issuing_rule->{renewalsallowed} <= $issue->renewals; + + return ( 0, "too_unseen" ) + if C4::Context->preference('UnseenRenewals') && + $issuing_rule->{unseen_renewals_allowed} && + $issuing_rule->{unseen_renewals_allowed} <= $issue->unseen_renewals; + + my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing'); + my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing'); + $patron = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful? + my $restricted = $patron->is_debarred; + my $hasoverdues = $patron->has_overdues; + + if ( $restricted and $restrictionblockrenewing ) { + return ( 0, 'restriction'); + } elsif ( ($hasoverdues and $overduesblockrenewing eq 'block') || ($issue->is_overdue and $overduesblockrenewing eq 'blockitem') ) { + return ( 0, 'overdue'); + } + + if ( $issue->auto_renew ) { + + if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) { + return ( 0, 'auto_account_expired' ); + } + + if ( defined $issuing_rule->{no_auto_renewal_after} + and $issuing_rule->{no_auto_renewal_after} ne "" ) { + # Get issue_date and add no_auto_renewal_after + # If this is greater than today, it's too late for renewal. + my $maximum_renewal_date = dt_from_string($issue->issuedate, 'sql'); + $maximum_renewal_date->add( + $issuing_rule->{lengthunit} => $issuing_rule->{no_auto_renewal_after} + ); + my $now = dt_from_string; + if ( $now >= $maximum_renewal_date ) { + return ( 0, "auto_too_late" ); + } + } + if ( defined $issuing_rule->{no_auto_renewal_after_hard_limit} + and $issuing_rule->{no_auto_renewal_after_hard_limit} ne "" ) { + # If no_auto_renewal_after_hard_limit is >= today, it's also too late for renewal + if ( dt_from_string >= dt_from_string( $issuing_rule->{no_auto_renewal_after_hard_limit} ) ) { + return ( 0, "auto_too_late" ); + } + } + + if ( C4::Context->preference('OPACFineNoRenewalsBlockAutoRenew') ) { + my $fine_no_renewals = C4::Context->preference("OPACFineNoRenewals"); + my $amountoutstanding = + C4::Context->preference("OPACFineNoRenewalsIncludeCredit") + ? $patron->account->balance + : $patron->account->outstanding_debits->total_outstanding; + if ( $amountoutstanding and $amountoutstanding > $fine_no_renewals ) { + return ( 0, "auto_too_much_oweing" ); + } + } + } + + if ( defined $issuing_rule->{norenewalbefore} + and $issuing_rule->{norenewalbefore} ne "" ) + { + + # Calculate soonest renewal by subtracting 'No renewal before' from due date + my $soonestrenewal = dt_from_string( $issue->date_due, 'sql' )->subtract( + $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} ); + + # Depending on syspref reset the exact time, only check the date + if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date' + and $issuing_rule->{lengthunit} eq 'days' ) + { + $soonestrenewal->truncate( to => 'day' ); + } + + if ( $soonestrenewal > DateTime->now( time_zone => C4::Context->tz() ) ) + { + return ( 0, "auto_too_soon" ) if $issue->auto_renew; + return ( 0, "too_soon" ); + } + elsif ( $issue->auto_renew ) { + return ( 0, "auto_renew" ); + } + } + + # Fallback for automatic renewals: + # If norenewalbefore is undef, don't renew before due date. + if ( $issue->auto_renew ) { + my $now = dt_from_string; + return ( 0, "auto_renew" ) + if $now >= dt_from_string( $issue->date_due, 'sql' ); + return ( 0, "auto_too_soon" ); + } + return ( 1, undef ); } =head2 AddRenewal - &AddRenewal($borrowernumber, $itemnumber, $branch, [$datedue], [$lastreneweddate]); + &AddRenewal($borrowernumber, $itemnumber, $branch, [$datedue], [$lastreneweddate], [$seen]); Renews a loan. @@ -2981,6 +3094,10 @@ syspref) If C<$datedue> is the empty string, C<&AddRenewal> will calculate the due date automatically from the book's item type. +C<$seen> is a boolean flag indicating if the item was seen or not during the renewal. This +informs the incrementing of the unseen_renewals column. If this flag is not supplied, we +fallback to a true value + =cut sub AddRenewal { @@ -2990,6 +3107,10 @@ sub AddRenewal { my $datedue = shift; my $lastreneweddate = shift || dt_from_string(); my $skipfinecalc = shift; + my $seen = shift; + + # Fallback on a 'seen' renewal + $seen = defined $seen && $seen == 0 ? 0 : 1; my $item_object = Koha::Items->find($itemnumber) or return; my $biblio = $item_object->biblio; @@ -3042,15 +3163,35 @@ sub AddRenewal { } ); + # Increment the unseen renewals, if appropriate + # We only do so if the syspref is enabled and + # a maximum value has been set in the circ rules + my $unseen_renewals = $issue->unseen_renewals; + if (C4::Context->preference('UnseenRenewals')) { + my $rule = Koha::CirculationRules->get_effective_rule( + { categorycode => $patron->categorycode, + itemtype => $item_object->effective_itemtype, + branchcode => $circ_library->branchcode, + rule_name => 'unseen_renewals_allowed' + } + ); + if (!$seen && $rule && $rule->rule_value) { + $unseen_renewals++; + } else { + # If the renewal is seen, unseen should revert to 0 + $unseen_renewals = 0; + } + } + # Update the issues record to have the new due date, and a new count # of how many times it has been renewed. my $renews = ( $issue->renewals || 0 ) + 1; - my $sth = $dbh->prepare("UPDATE issues SET date_due = ?, renewals = ?, lastreneweddate = ? + my $sth = $dbh->prepare("UPDATE issues SET date_due = ?, renewals = ?, unseen_renewals = ?, lastreneweddate = ? WHERE borrowernumber=? AND itemnumber=?" ); - $sth->execute( $datedue->strftime('%Y-%m-%d %H:%M'), $renews, $lastreneweddate, $borrowernumber, $itemnumber ); + $sth->execute( $datedue->strftime('%Y-%m-%d %H:%M'), $renews, $unseen_renewals, $lastreneweddate, $borrowernumber, $itemnumber ); # Update the renewal count on the item, and tell zebra to reindex $renews = ( $item_object->renewals || 0 ) + 1; @@ -3137,8 +3278,11 @@ sub GetRenewCount { my ( $bornum, $itemno ) = @_; my $dbh = C4::Context->dbh; my $renewcount = 0; + my $unseencount = 0; my $renewsallowed = 0; + my $unseenallowed = 0; my $renewsleft = 0; + my $unseenleft = 0; my $patron = Koha::Patrons->find( $bornum ); my $item = Koha::Items->find($itemno); @@ -3157,22 +3301,34 @@ sub GetRenewCount { $sth->execute( $bornum, $itemno ); my $data = $sth->fetchrow_hashref; $renewcount = $data->{'renewals'} if $data->{'renewals'}; + $unseencount = $data->{'unseen_renewals'} if $data->{'unseen_renewals'}; # $item and $borrower should be calculated my $branchcode = _GetCircControlBranch($item->unblessed, $patron->unblessed); - my $rule = Koha::CirculationRules->get_effective_rule( + my $rules = Koha::CirculationRules->get_effective_rules( { categorycode => $patron->categorycode, itemtype => $item->effective_itemtype, branchcode => $branchcode, - rule_name => 'renewalsallowed', + rules => [ 'renewalsallowed', 'unseen_renewals_allowed' ] } ); - - $renewsallowed = $rule ? $rule->rule_value : 0; + $renewsallowed = $rules ? $rules->{renewalsallowed} : 0; + $unseenallowed = $rules->{unseen_renewals_allowed} ? + $rules->{unseen_renewals_allowed} : + 0; $renewsleft = $renewsallowed - $renewcount; + $unseenleft = $unseenallowed - $unseencount; if($renewsleft < 0){ $renewsleft = 0; } - return ( $renewcount, $renewsallowed, $renewsleft ); + if($unseenleft < 0){ $unseenleft = 0; } + return ( + $renewcount, + $renewsallowed, + $renewsleft, + $unseencount, + $unseenallowed, + $unseenleft + ); } =head2 GetSoonestRenewDate diff --git a/C4/ILSDI/Services.pm b/C4/ILSDI/Services.pm index bc5cb8676d..1e596932ba 100644 --- a/C4/ILSDI/Services.pm +++ b/C4/ILSDI/Services.pm @@ -669,7 +669,7 @@ sub RenewLoan { # Add renewal if possible my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber ); - if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber ); } + if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef, 0 ); } my $issue = $item->checkout; return unless $issue; # FIXME should be handled diff --git a/C4/SIP/ILS/Transaction/Renew.pm b/C4/SIP/ILS/Transaction/Renew.pm index 7a21c89144..e950424d74 100644 --- a/C4/SIP/ILS/Transaction/Renew.pm +++ b/C4/SIP/ILS/Transaction/Renew.pm @@ -51,6 +51,7 @@ sub do_renew_for { } else { $renewerror=~s/on_reserve/Item unavailable due to outstanding holds/; $renewerror=~s/too_many/Item has reached maximum renewals/; + $renewerror=~s/too_unseen/Item has reached maximum consecutive renewals without being seen/; $renewerror=~s/item_denied_renewal/Item renewal is not allowed/; $self->screen_msg($renewerror); $self->renewal_ok(0); diff --git a/Koha/CirculationRules.pm b/Koha/CirculationRules.pm index e0d895325b..df1314613e 100644 --- a/Koha/CirculationRules.pm +++ b/Koha/CirculationRules.pm @@ -151,6 +151,9 @@ our $RULE_KINDS = { renewalsallowed => { scope => [ 'branchcode', 'categorycode', 'itemtype' ], }, + unseen_renewals_allowed => { + scope => [ 'branchcode', 'categorycode', 'itemtype' ], + }, rentaldiscount => { scope => [ 'branchcode', 'categorycode', 'itemtype' ], }, diff --git a/Koha/REST/V1/Checkouts.pm b/Koha/REST/V1/Checkouts.pm index 9d5e5b42a1..93feeaeb24 100644 --- a/Koha/REST/V1/Checkouts.pm +++ b/Koha/REST/V1/Checkouts.pm @@ -146,6 +146,7 @@ sub renew { my $c = shift->openapi->valid_input or return; my $checkout_id = $c->validation->param('checkout_id'); + my $seen = $c->validation->param('seen') || 1; my $checkout = Koha::Checkouts->find( $checkout_id ); unless ($checkout) { @@ -169,7 +170,14 @@ sub renew { ); } - AddRenewal($borrowernumber, $itemnumber, $checkout->branchcode); + AddRenewal( + $borrowernumber, + $itemnumber, + $checkout->branchcode, + undef, + undef, + $seen + ); $checkout = Koha::Checkouts->find($checkout_id); $c->res->headers->location( $c->req->url->to_string ); @@ -223,6 +231,7 @@ sub allows_renewal { allows_renewal => $renewable, max_renewals => $rule->rule_value, current_renewals => $checkout->renewals, + unseen_renewals => $checkout->unseen_renewals, error => $error } ); diff --git a/api/v1/swagger/definitions/checkout.json b/api/v1/swagger/definitions/checkout.json index 071e62cc5d..6976d5da5f 100644 --- a/api/v1/swagger/definitions/checkout.json +++ b/api/v1/swagger/definitions/checkout.json @@ -39,6 +39,10 @@ "type": ["integer", "null"], "description": "Number of renewals" }, + "unseen_renewals": { + "type": ["integer", "null"], + "description": "Number of consecutive unseen renewals" + }, "auto_renew": { "type": "boolean", "description": "Auto renewal" diff --git a/api/v1/swagger/parameters.json b/api/v1/swagger/parameters.json index b39ba87cd1..ddced814d0 100644 --- a/api/v1/swagger/parameters.json +++ b/api/v1/swagger/parameters.json @@ -41,6 +41,9 @@ "checkout_id_pp": { "$ref": "parameters/checkout.json#/checkout_id_pp" }, + "seen_pp": { + "$ref": "parameters/checkout.json#/seen_pp" + }, "match": { "name": "_match", "in": "query", diff --git a/api/v1/swagger/parameters/checkout.json b/api/v1/swagger/parameters/checkout.json index 2bdb20ab84..3b802f0c30 100644 --- a/api/v1/swagger/parameters/checkout.json +++ b/api/v1/swagger/parameters/checkout.json @@ -5,5 +5,12 @@ "description": "Internal checkout identifier", "required": true, "type": "integer" + }, + "seen_pp": { + "name": "seen", + "in": "query", + "description": "Item was seen flag", + "required": false, + "type": "integer" } } diff --git a/api/v1/swagger/paths/checkouts.json b/api/v1/swagger/paths/checkouts.json index 73b5dfab86..cc2841b28d 100644 --- a/api/v1/swagger/paths/checkouts.json +++ b/api/v1/swagger/paths/checkouts.json @@ -87,9 +87,10 @@ "x-mojo-to": "Checkouts#renew", "operationId": "renewCheckout", "tags": ["patrons", "checkouts"], - "parameters": [{ - "$ref": "../parameters.json#/checkout_id_pp" - }], + "parameters": [ + { "$ref": "../parameters.json#/checkout_id_pp" }, + { "$ref": "../parameters.json#/seen_pp" } + ], "produces": ["application/json"], "responses": { "201": { diff --git a/circ/renew.pl b/circ/renew.pl index 1d6bdee076..28a25c2846 100755 --- a/circ/renew.pl +++ b/circ/renew.pl @@ -43,6 +43,7 @@ my ( $template, $librarian, $cookie, $flags ) = get_template_and_user( my $schema = Koha::Database->new()->schema(); my $barcode = $cgi->param('barcode'); +my $unseen = $cgi->param('unseen') || 0; $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespae $barcode = barcodedecode($barcode) if( $barcode && C4::Context->preference('itemBarcodeInputFilter')); my $override_limit = $cgi->param('override_limit'); @@ -102,7 +103,15 @@ if ($barcode) { if ( C4::Context->preference('SpecifyDueDate') && $hard_due_date ) { $date_due = dt_from_string( $hard_due_date ); } - $date_due = AddRenewal( undef, $item->itemnumber(), $branchcode, $date_due ); + $date_due = AddRenewal( + undef, + $item->itemnumber(), + $branchcode, + $date_due, + undef, + undef, + !$unseen + ); $template->param( date_due => $date_due ); } } diff --git a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss index 1b6a2ba8ef..f72cf40720 100644 --- a/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss +++ b/koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss @@ -1025,6 +1025,10 @@ div { width: auto; } + .renew_formfield { + margin-bottom: 1em; + } + .circmessage { margin-bottom: .3em; padding: 0 .4em .4em; @@ -2489,6 +2493,14 @@ li { position: relative; } +#renew_as_unseen_label { + margin-left: 1em; +} + +#renew_as_unseen_checkbox { + margin-right: 1em; +} + #clearscreen { position: absolute; right: 0; diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc index c3d77ca7db..38a4700416 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc @@ -49,6 +49,10 @@ [% END %] [% END %] [% IF ( CAN_user_circulate_circulate_remaining_permissions ) %] + [% IF Koha.Preference( 'UnseenRenewals' ) %] + + + [% END %] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt index ec3cd044be..0a7d40c8a8 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -1078,6 +1078,7 @@ var logged_in_user_borrowernumber = "[% logged_in_user.borrowernumber | html %]"; var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]"; var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]"; + var UnseenRenewals = "[% Koha.Preference('UnseenRenewals') | html %]"; var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]"; var interface = "[% interface | html %]"; var theme = "[% theme | html %]"; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt index 08d12ad0c2..3ff63d043a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt @@ -52,6 +52,18 @@ [% END %] + [% ELSIF error == "too_unseen" %] + +

[% INCLUDE 'biblio-title.inc' biblio=item.biblio %] ( [% item.barcode | html %] ) has been renewed the maximum number of consecutive times without being seen by the library )

+ + [% IF Koha.Preference('AllowRenewalLimitOverride') %] +
+ + + +
+ [% END %] + [% ELSIF error == "too_soon" %]

[% INCLUDE 'biblio-title.inc' biblio=item.biblio link = 1 %] ( [% item.barcode | html %] ) cannot be renewed before [% soonestrenewdate | $KohaDates %].

@@ -169,12 +181,25 @@

Renew

-
- -
- - - + [% IF Koha.Preference('UnseenRenewals') %] +
+
+ +
+ +
+
+ + +
+ [% ELSE %] +
+ +
+ + + + [% END %]
@@ -184,7 +209,6 @@
-
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt index 85fc32f61a..7b7fd26e67 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt @@ -920,6 +920,7 @@ var ClaimReturnedLostValue = "[% Koha.Preference('ClaimReturnedLostValue') | html %]"; var ClaimReturnedChargeFee = "[% Koha.Preference('ClaimReturnedChargeFee') | html %]"; var ClaimReturnedWarningThreshold = "[% Koha.Preference('ClaimReturnedWarningThreshold') | html %]"; + var UnseenRenewals = "[% Koha.Preference('UnseenRenewals') | html %]"; var interface = "[% interface | html %]"; var theme = "[% theme | html %]"; var borrowernumber = "[% patron.borrowernumber | html %]"; diff --git a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js index b4077ce9ac..52daaacb87 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -152,9 +152,15 @@ $(document).ready(function() { itemnumber: itemnumber, borrowernumber: borrowernumber, branchcode: branchcode, - override_limit: override_limit, + override_limit: override_limit }; + if (UnseenRenewals) { + var ren = $("#renew_as_unseen_checkbox"); + var renew_unseen = ren.length > 0 && ren.is(':checked') ? 1 : 0; + params.seen = renew_unseen === 1 ? 0 : 1; + } + // Determine which due date we need to use var dueDate = isOnReserve ? $("#newonholdduedate input").val() : @@ -177,6 +183,8 @@ $(document).ready(function() { content += __("not checked out"); } else if ( data.error == "too_many" ) { content += __("too many renewals"); + } else if ( data.error == "too_unseen" ) { + content += __("too many consecutive renewals without being seen by the library"); } else if ( data.error == "on_reserve" ) { content += __("on hold"); } else if ( data.error == "restriction" ) { @@ -445,6 +453,13 @@ $(document).ready(function() { + __("Not renewable") + ""; + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "too_unseen" ) { + msg += "" + + __("Must be renewed at the library") + + ""; + span_style = "display: none"; span_class = "renewals-allowed"; } else if ( oObj.can_renew_error == "restriction" ) { @@ -541,8 +556,11 @@ $(document).ready(function() { } content += msg; if ( can_renew || can_force_renew ) { - content += "(" - + __("%s of %s renewals remaining").format(oObj.renewals_remaining, oObj.renewals_allowed) + content += "("; + content + __("%s of %s renewals remaining").format(oObj.renewals_remaining, oObj.renewals_allowed); + if (UnseenRenewals && oObj.unseen_allowed) { + content += __(" / %s of %s unseen renewals remaining").format(oObj.unseen_remaining, oObj.unseen_allowed); + } + ")"; } diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt index 548af38171..705a7f44ec 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt @@ -95,6 +95,8 @@
  • Your account has expired. Please contact the library for more information.
  • [% ELSIF error == 'too_many' %]
  • You have renewed this item the maximum number of times allowed.
  • + [% ELSIF error == 'too_unseen' %] +
  • You have renewed this item the maximum number of consecutive times without it being seen by the library.
  • [% ELSIF error == 'too_soon' %]
  • It is too soon after the checkout date for this item to be renewed.
  • [% ELSIF error == 'on_reserve' %] @@ -366,7 +368,12 @@ [% IF ISSUE.itemtype_object.rentalcharge_hourly > 0 %] [% ISSUE.itemtype_object.rentalcharge_hourly | $Price %] per hour [% END %] - ([% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining) + ( + [% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining + [% IF Koha.Preference('UnseenRenewals') && ISSUE.unseenallowed %] + / [% ISSUE.unseenleft | html %] of [% ISSUE.unseenallowed | html %] renewals left before the item must be seen by the library + [% END %] + ) [% ELSIF ( ISSUE.on_reserve ) %] Not renewable (on hold) [% ELSIF ( ISSUE.too_many ) %] @@ -377,16 +384,36 @@ No longer renewable [% ELSIF ISSUE.auto_too_much_oweing %] Automatic renewal failed, you have unpaid fines. - ([% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining) + ( + [% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining + [% IF Koha.Preference('UnseenRenewals') && ISSUE.unseenallowed %] + / [% ISSUE.unseenleft | html %] of [% ISSUE.unseenallowed | html %] renewals left before the item must be seen by the library + [% END %] + ) [% ELSIF ISSUE.auto_account_expired %] Automatic renewal failed, your account is expired. - ([% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining) + ( + [% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining + [% IF Koha.Preference('UnseenRenewals') && ISSUE.unseenallowed %] + / [% ISSUE.unseenleft | html %] of [% ISSUE.unseenallowed | html %] renewals left before the item must be seen by the library + [% END %] + ) [% ELSIF ( ISSUE.too_soon ) %] No renewal before [% ISSUE.soonestrenewdate | html %] - ([% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining) + ( + [% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining + [% IF Koha.Preference('UnseenRenewals') && ISSUE.unseenallowed %] + / [% ISSUE.unseenleft | html %] of [% ISSUE.unseenallowed | html %] renewals left before the item must be seen by the library + [% END %] + ) [% ELSIF ( ISSUE.auto_renew || ISSUE.auto_too_soon ) %] Automatic renewal - ([% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining) + ( + [% ISSUE.renewsleft | html %] of [% ISSUE.renewsallowed | html %] renewals remaining + [% IF Koha.Preference('UnseenRenewals') && ISSUE.unseenallowed %] + / [% ISSUE.unseenleft | html %] of [% ISSUE.unseenallowed | html %] renewals left before the item must be seen by the library + [% END %] + ) [% ELSIF ( ISSUE.item_denied_renewal ) %] Renewal not allowed [% END %] @@ -641,7 +668,12 @@ [% IF ( canrenew ) %] Renew [% END %] - ([% OVERDUE.renewsleft | html %] of [% OVERDUE.renewsallowed | html %] renewals remaining) + ( + [% OVERDUE.renewsleft | html %] of [% OVERDUE.renewsallowed | html %] renewals remaining + [% IF Koha.Preference('UnseenRenewals') && ISSUE.unseenallowed %] + / [% OVERDUE.unseenleft | html %] of [% OVERDUE.unseenallowed | html %] renewals left before the item must be seen by the library + [% END %] + ) [% ELSIF ( OVERDUE.norenew_overdue ) %] Not allowed(overdue) [% ELSIF ( OVERDUE.onreserve ) %] diff --git a/misc/cronjobs/automatic_renewals.pl b/misc/cronjobs/automatic_renewals.pl index 1c47cfd680..a1027848ad 100755 --- a/misc/cronjobs/automatic_renewals.pl +++ b/misc/cronjobs/automatic_renewals.pl @@ -95,7 +95,7 @@ while ( my $auto_renew = $auto_renews->next ) { $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber; } if ($confirm){ - my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode ); + my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode, undef, undef, 0 ); $auto_renew->auto_renew_error(undef)->store; } push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew; diff --git a/offline_circ/download.pl b/offline_circ/download.pl index 63ed34bdb6..838e63ee08 100755 --- a/offline_circ/download.pl +++ b/offline_circ/download.pl @@ -67,6 +67,7 @@ my $issues_query = q{SELECT issues.date_due AS date_due, issues.issuedate AS issuedate, issues.renewals AS renewals, + issues.unseen_renewals AS unseen_renewals, borrowers.cardnumber AS cardnumber, CONCAT(borrowers.surname, ', ', borrowers.firstname) AS borrower_name FROM issues diff --git a/opac/opac-renew.pl b/opac/opac-renew.pl index 55b20ebdfd..ea8dbde961 100755 --- a/opac/opac-renew.pl +++ b/opac/opac-renew.pl @@ -62,7 +62,7 @@ else { my ( $status, $error ) = CanBookBeRenewed( $borrowernumber, $itemnumber ); if ( $status == 1 && $opacrenew == 1 ) { - AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef ); + AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef, undef, 0 ); push( @renewed, $itemnumber ); } else { diff --git a/opac/opac-user.pl b/opac/opac-user.pl index fd15abd95c..7a9c774d67 100755 --- a/opac/opac-user.pl +++ b/opac/opac-user.pl @@ -223,7 +223,14 @@ if ( $pending_checkouts->count ) { # Useless test # check if item is renewable my ($status,$renewerror) = CanBookBeRenewed( $borrowernumber, $issue->{'itemnumber'} ); - ($issue->{'renewcount'},$issue->{'renewsallowed'},$issue->{'renewsleft'}) = GetRenewCount($borrowernumber, $issue->{'itemnumber'}); + ( + $issue->{'renewcount'}, + $issue->{'renewsallowed'}, + $issue->{'renewsleft'}, + $issue->{'unseencount'}, + $issue->{'unseenallowed'}, + $issue->{'unseenleft'} + ) = GetRenewCount($borrowernumber, $issue->{'itemnumber'}); ( $issue->{'renewalfee'}, $issue->{'renewalitemtype'} ) = GetIssuingCharges( $issue->{'itemnumber'}, $borrowernumber ); $issue->{itemtype_object} = Koha::ItemTypes->find( Koha::Items->find( $issue->{itemnumber} )->effective_itemtype ); if($status && C4::Context->preference("OpacRenewalAllowed")){ @@ -235,6 +242,7 @@ if ( $pending_checkouts->count ) { # Useless test if ($renewerror) { $issue->{'too_many'} = 1 if $renewerror eq 'too_many'; + $issue->{'too_unseen'} = 1 if $renewerror eq 'too_unseen'; $issue->{'on_reserve'} = 1 if $renewerror eq 'on_reserve'; $issue->{'norenew_overdue'} = 1 if $renewerror eq 'overdue'; $issue->{'auto_renew'} = 1 if $renewerror eq 'auto_renew'; diff --git a/svc/checkouts b/svc/checkouts index 611b28d2af..f54567ff5f 100755 --- a/svc/checkouts +++ b/svc/checkouts @@ -163,7 +163,14 @@ while ( my $c = $sth->fetchrow_hashref() ) { ) : undef; - my ( $renewals_count, $renewals_allowed, $renewals_remaining ) = + my ( + $renewals_count, + $renewals_allowed, + $renewals_remaining, + $unseen_count, + $unseen_allowed, + $unseen_remaining + ) = GetRenewCount( $c->{borrowernumber}, $c->{itemnumber} ); my ( $itemtype, $recordtype, $type_for_stat ); @@ -242,6 +249,9 @@ while ( my $c = $sth->fetchrow_hashref() ) { renewals_count => $renewals_count, renewals_allowed => $renewals_allowed, renewals_remaining => $renewals_remaining, + unseen_count => $unseen_count, + unseen_allowed => $unseen_allowed, + unseen_remaining => $unseen_remaining, return_claim_id => $c->{return_claim_id}, return_claim_notes => $c->{return_claim_notes}, diff --git a/svc/renew b/svc/renew index 786ce57202..3e63f2e5d8 100755 --- a/svc/renew +++ b/svc/renew @@ -46,6 +46,7 @@ my $borrowernumber = $input->param('borrowernumber'); my $override_limit = $input->param('override_limit'); my $branchcode = $input->param('branchcode') || C4::Context->userenv->{'branch'}; +my $seen = $input->param('seen'); my $date_due; if ( $input->param('date_due') ) { $date_due = dt_from_string( scalar $input->param('date_due') ); @@ -66,7 +67,7 @@ if ( $data->{error} && $data->{error} eq 'on_reserve' && C4::Context->preference } if ( $data->{renew_okay} ) { - $date_due = AddRenewal( $borrowernumber, $itemnumber, $branchcode, $date_due ); + $date_due = AddRenewal( $borrowernumber, $itemnumber, $branchcode, $date_due, undef, $seen ); $data->{date_due} = output_pref( { dt => $date_due, as_due_date => 1 } ); } -- 2.39.5