From 5e4290597d7bb9bab8cd9ebf261ed0cac34ef12f 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 --- 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/includes/strings.inc | 3 + .../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 | 26 ++- .../bootstrap/en/modules/opac-user.tt | 46 ++++- 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 +- 24 files changed, 346 insertions(+), 36 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 3571051e84..65f7fda7f0 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -2664,6 +2664,7 @@ sub CanBookBeRenewed { 'no_auto_renewal_after_hard_limit', 'lengthunit', 'norenewalbefore', + 'unseen_renewals_allowed' ] } ); @@ -2836,12 +2837,124 @@ sub CanBookBeRenewed { return ( 0, "on_reserve" ) if $resfound; # '' when no hold was found return ( 0, "auto_renew" ) if $auto_renew && !$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. @@ -2866,6 +2979,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 { @@ -2875,6 +2992,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; @@ -2927,15 +3048,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; @@ -3022,8 +3163,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); @@ -3042,22 +3186,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 5ebba3435d..e0d54914c3 100644 --- a/C4/ILSDI/Services.pm +++ b/C4/ILSDI/Services.pm @@ -655,7 +655,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 87062f541a..283cc1bcc0 100644 --- a/Koha/CirculationRules.pm +++ b/Koha/CirculationRules.pm @@ -148,6 +148,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 42b9598843..fb98afd28e 100644 --- a/api/v1/swagger/definitions/checkout.json +++ b/api/v1/swagger/definitions/checkout.json @@ -35,6 +35,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 cab2d53b47..7d1e13b385 100644 --- a/api/v1/swagger/parameters.json +++ b/api/v1/swagger/parameters.json @@ -35,6 +35,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 ca6d970dbb..a97b9f0572 100644 --- a/api/v1/swagger/paths/checkouts.json +++ b/api/v1/swagger/paths/checkouts.json @@ -81,9 +81,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 29824187a8..58a16f8538 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 9a7470546e..de72fbdf43 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; @@ -2482,6 +2486,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 7b967bec89..3183ff735c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/checkouts-table.inc @@ -48,6 +48,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/includes/strings.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc index 26aed46765..1f9c3aad38 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/strings.inc @@ -12,6 +12,7 @@ var RETURN_CLAIMED_NOTES = _("Notes about return claim"); var NOT_CHECKED_OUT = _("not checked out"); var TOO_MANY_RENEWALS = _("too many renewals"); + var TOO_MANY_UNSEEN = _("too many consecutive renewals without being seen by the library"); var ON_RESERVE = _("on hold"); var REASON_UNKNOWN = _("reason unknown"); var TODAYS_CHECKOUTS = _("Today's checkouts"); @@ -20,6 +21,7 @@ var ON_HOLD = _("On hold"); var PLACE_HOLD = _("Place hold"); var NOT_RENEWABLE = _("Not renewable"); + var NOT_RENEWABLE_UNSEEN = _("Must be renewed at the library"); var NOT_RENEWABLE_TOO_SOON = _("No renewal before %s"); var NOT_RENEWABLE_AUTO_TOO_SOON = _("Scheduled for automatic renewal"); var NOT_RENEWABLE_AUTO_TOO_LATE = _("Can no longer be auto-renewed - number of checkout days exceeded"); @@ -28,6 +30,7 @@ var NOT_RENEWABLE_AUTO_RENEW = _("Scheduled for automatic renewal"); var NOT_RENEWABLE_DENIED = _("Renewal denied by syspref"); var RENEWALS_REMAINING = _("%s of %s renewals remaining"); + var UNSEEN_REMAINING = _("%s of %s unseen renewals remaining"); var HOLD_IS_SUSPENDED = _("Hold is suspended"); var UNTIL = _("until %s"); var NEXT_AVAILABLE_ITYPE = _("Next available %s item"); 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 3be17a8051..8bac03de8c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -1058,6 +1058,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 717b815fd2..4fc969661d 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 %] ( [% 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 dede8601fc..7f5e5a4477 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt @@ -925,6 +925,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 03c0e6242f..dc50aa86e5 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js +++ b/koha-tmpl/intranet-tmpl/prog/js/checkouts.js @@ -143,9 +143,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() : @@ -168,6 +174,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_UNSEEN; } else if ( data.error == "on_reserve" ) { content += ON_RESERVE; } else if ( data.error == "restriction" ) { @@ -431,6 +439,13 @@ $(document).ready(function() { + NOT_RENEWABLE + ""; + span_style = "display: none"; + span_class = "renewals-allowed"; + } else if ( oObj.can_renew_error == "too_unseen" ) { + msg += "" + + NOT_RENEWABLE_UNSEEN + + ""; + span_style = "display: none"; span_class = "renewals-allowed"; } else if ( oObj.can_renew_error == "restriction" ) { @@ -527,9 +542,12 @@ $(document).ready(function() { } content += msg; if ( can_renew || can_force_renew ) { - content += "(" - + RENEWALS_REMAINING.format( oObj.renewals_remaining, oObj.renewals_allowed ) - + ")"; + content += "("; + content += RENEWALS_REMAINING.format( oObj.renewals_remaining, oObj.renewals_allowed ); + if (UnseenRenewals && oObj.unseen_allowed) { + content += " / " + UNSEEN_REMAINING.format( oObj.unseen_remaining, oObj.unseen_allowed ); + } + content += ")"; } content += ""; 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 13cd1843ee..cb05593448 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' %] @@ -360,27 +362,54 @@ [% 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 ) %] Not renewable + [% ELSIF ( ISSUE.too_unseen ) %] + Item must be seen by the library [% ELSIF ( ISSUE.norenew_overdue ) %] Not allowed (overdue) [% ELSIF ( ISSUE.auto_too_late ) %] 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 %] @@ -635,7 +664,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 a76f7dfb35..4c7b040804 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 386faebf41..1c3f0f2d79 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 b1111d0e07..9fa3bdd56f 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 a380d88f01..da2d030cde 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 fa470b3a2a..4a6d5179ab 100755 --- a/svc/checkouts +++ b/svc/checkouts @@ -158,7 +158,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 $type_for_stat = Koha::ItemTypes->find( $item_level_itypes ? $c->{itype} : $c->{itemtype} ); @@ -225,6 +232,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 51b915b004..98d7498a7c 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.20.1