Bug 23415: Add debt override support to circulation checkout page
This patch implements fine override functionality for the checkouts
table on the circulation page (circ/circulation.pl), completing the
debt override feature for all renewal workflows.
Changes:
- Added override_debt checkbox to checkouts-table.inc when
AllowFineOverrideRenewing preference is enabled
- Updated /svc/renew to accept and process override_debt parameter,
matching the pattern used for override_limit
- Enhanced circulation-api-client.js to pass override_debt parameter
through the renewal API call
- Implemented specific CSS classes for renewal error types
(renewals-allowed-too_many, renewals-allowed-too_much_owing, etc.)
to enable selective checkbox control
- Modified override checkbox handlers to selectively enable only
relevant renewal checkboxes based on the specific blocking error:
* override_limit enables checkboxes for 'too_many' and 'on_reserve'
* override_debt enables checkboxes for 'too_much_owing' and
'auto_too_much_owing'
- Added AllowFineOverrideRenewing JavaScript variable to circulation.tt
This provides clear visual feedback to staff about which renewals will
be affected by each override option, improving usability and reducing
confusion when multiple items have different blocking reasons.
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
This commit is contained in:
parent
4b88b1de3d
commit
8b35dfcc9d
|
|
@ -53,7 +53,7 @@ my $hard_due_date = $cgi->param('hard_due_date');
|
|||
|
||||
my ( $item, $checkout, $patron );
|
||||
my $error = q{};
|
||||
my ( $soonest_renew_date, $latest_auto_renew_date, $balance );
|
||||
my ( $soonest_renew_date, $latest_auto_renew_date );
|
||||
|
||||
if ( $op eq 'cud-renew' && $barcode ) {
|
||||
$barcode = barcodedecode($barcode) if $barcode;
|
||||
|
|
@ -100,8 +100,6 @@ if ( $op eq 'cud-renew' && $barcode ) {
|
|||
$can_renew = 1;
|
||||
$error = undef;
|
||||
} else {
|
||||
$balance = $patron->account->balance;
|
||||
$template->param( balance => $balance );
|
||||
$can_renew = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@
|
|||
<label for="override_limit">Override renewal restrictions:</label>
|
||||
<input type="checkbox" name="override_limit" id="override_limit" value="1" />
|
||||
[% END %]
|
||||
[% IF Koha.Preference( 'AllowFineOverrideRenewing' ) %]
|
||||
<label for="override_debt">Override fine restrictions:</label>
|
||||
<input type="checkbox" name="override_debt" id="override_debt" value="1" />
|
||||
[% END %]
|
||||
[% END %]
|
||||
[% IF ( CAN_user_circulate_circulate_remaining_permissions ) %]
|
||||
[% IF Koha.Preference( 'UnseenRenewals' ) %]
|
||||
|
|
@ -76,6 +80,12 @@
|
|||
<button class="btn btn-default" id="RenewAll"><i class="fa fa-book"></i> Renew all</button>
|
||||
[% END %]
|
||||
</fieldset>
|
||||
[% IF patron.account.non_issues_charges >= Koha.Preference('FineNoRenewals') %]
|
||||
<p
|
||||
><strong>Note: </strong> Patron has <strong><span id="patron-non-issues-charges">[% patron.account.non_issues_charges | $Price %]</span></strong> of non-issuing charges outstanding, renewals are restricted at
|
||||
<strong><span id="fine-no-renewals-limit">[% Koha.Preference('FineNoRenewals') | $Price %]</span></strong></p
|
||||
>
|
||||
[% END %]
|
||||
|
||||
[% IF Koha.Preference('ExportCircHistory') %]
|
||||
<fieldset>
|
||||
|
|
|
|||
|
|
@ -1096,6 +1096,7 @@
|
|||
var exports_enabled = [% Koha.Preference('ExportCircHistory') ? 1 : 0 | html %];
|
||||
var AllowRenewalLimitOverride = [% (CAN_user_circulate_override_renewals && Koha.Preference('AllowRenewalLimitOverride') )? 1: 0 | html %];
|
||||
var AllowRenewalOnHoldOverride = [% (CAN_user_circulate_override_renewals && Koha.Preference('AllowRenewalOnHoldOverride') )? 1: 0 | html %];
|
||||
var AllowFineOverrideRenewing = [% (CAN_user_circulate_override_renewals && Koha.Preference('AllowFineOverrideRenewing') )? 1: 0 | html %];
|
||||
var AllowCirculate = [% (CAN_user_circulate_circulate_remaining_permissions)? 1 : 0 | html %];
|
||||
var script = "circulation";
|
||||
var relatives_borrowernumbers = new Array();
|
||||
|
|
|
|||
|
|
@ -129,11 +129,14 @@
|
|||
[% ELSIF error == "auto_renew" or error == "auto_too_much_owing" %]
|
||||
<p>[% INCLUDE 'biblio-title.inc' biblio=item.biblio link = 1 %] ( [% item.barcode | html %] ) has been scheduled for automatic renewal. </p>
|
||||
[% IF error == "auto_too_much_owing" %]
|
||||
[% IF balance %]
|
||||
<ul>
|
||||
<li>The patron has a debt of [% balance | $Price %] and renewals are restricted at [% Koha.Preference('FineNoRenewals') | $Price %].</li>
|
||||
</ul>
|
||||
[% END %]
|
||||
[% SET patron_account = borrower.account %]
|
||||
[% SET total_balance = patron_account.balance %]
|
||||
[% SET non_issues_charges = patron_account.non_issues_charges %]
|
||||
[% SET fine_no_renewals = Koha.Preference('FineNoRenewals') %]
|
||||
<ul>
|
||||
<li>The patron has a total debt of [% total_balance | $Price %], of which [% non_issues_charges | $Price %] are non-issuing charges.</li>
|
||||
<li>Renewals are blocked when non-issuing charges exceed [% fine_no_renewals | $Price %].</li>
|
||||
</ul>
|
||||
[% IF Koha.Preference('AllowFineOverrideRenewing') %]
|
||||
<form method="post" action="/cgi-bin/koha/circ/renew.pl">
|
||||
[% INCLUDE 'csrf-token.inc' %]
|
||||
|
|
@ -156,8 +159,13 @@
|
|||
[% END %]
|
||||
[% END %]
|
||||
[% ELSIF error == "too_much_owing" %]
|
||||
[% SET patron_account = borrower.account %]
|
||||
[% SET total_balance = patron_account.balance %]
|
||||
[% SET non_issues_charges = patron_account.non_issues_charges %]
|
||||
[% SET fine_no_renewals = Koha.Preference('FineNoRenewals') %]
|
||||
<ul>
|
||||
<li>The patron has a debt of [% balance | $Price %] and renewals are restricted at [% Koha.Preference('FineNoRenewals') | $Price %].</li>
|
||||
<li>The patron has a total debt of [% total_balance | $Price %], of which [% non_issues_charges | $Price %] are non-issuing charges.</li>
|
||||
<li>Renewals are blocked when non-issuing charges exceed [% fine_no_renewals | $Price %].</li>
|
||||
</ul>
|
||||
[% IF Koha.Preference('AllowFineOverrideRenewing') %]
|
||||
<form method="post" action="/cgi-bin/koha/circ/renew.pl">
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ function LoadIssuesTable() {
|
|||
"</span>";
|
||||
|
||||
span_style = "display: none";
|
||||
span_class = "renewals-allowed";
|
||||
span_class = "renewals-allowed-too_many";
|
||||
} else if (oObj.can_renew_error == "too_unseen") {
|
||||
msg +=
|
||||
"<span>" +
|
||||
|
|
@ -478,7 +478,7 @@ function LoadIssuesTable() {
|
|||
"</span>";
|
||||
|
||||
span_style = "display: none";
|
||||
span_class = "renewals-allowed";
|
||||
span_class = "renewals-allowed-auto_too_much_owing";
|
||||
} else if (
|
||||
oObj.can_renew_error == "auto_account_expired"
|
||||
) {
|
||||
|
|
@ -507,13 +507,12 @@ function LoadIssuesTable() {
|
|||
msg +=
|
||||
"<span class='renewals-disabled'>" +
|
||||
__(
|
||||
"Cannot renew, the patron has a debt of " +
|
||||
parseFloat(oObj.fine).format_price()
|
||||
"Cannot renew - patron has debts blocking renewal"
|
||||
) +
|
||||
"</span>";
|
||||
|
||||
span_style = "display: none";
|
||||
span_class = "renewals-allowed";
|
||||
span_class = "renewals-allowed-too_much_owing";
|
||||
} else {
|
||||
msg +=
|
||||
"<span class='renewals-disabled'>" +
|
||||
|
|
@ -1010,6 +1009,7 @@ $(document).ready(function () {
|
|||
|
||||
function renew(item_id) {
|
||||
var override_limit = $("#override_limit").is(":checked") ? 1 : 0;
|
||||
var override_debt = $("#override_debt").is(":checked") ? 1 : 0;
|
||||
|
||||
$(this)
|
||||
.parent()
|
||||
|
|
@ -1029,6 +1029,7 @@ $(document).ready(function () {
|
|||
patron_id: borrowernumber,
|
||||
library_id: branchcode,
|
||||
override_limit: override_limit,
|
||||
override_debt: override_debt,
|
||||
};
|
||||
|
||||
if (UnseenRenewals) {
|
||||
|
|
@ -1420,16 +1421,28 @@ $(document).ready(function () {
|
|||
.click(function () {
|
||||
if (this.checked) {
|
||||
if (AllowRenewalLimitOverride) {
|
||||
$(".renewals-allowed").show();
|
||||
$(".renewals-disabled").hide();
|
||||
$(".renewals-allowed-too_many").show();
|
||||
}
|
||||
if (AllowRenewalOnHoldOverride) {
|
||||
$(".renewals-allowed-on_reserve").show();
|
||||
}
|
||||
} else {
|
||||
$(".renewals-allowed").hide();
|
||||
$(".renewals-allowed-too_many").hide();
|
||||
$(".renewals-allowed-on_reserve").hide();
|
||||
$(".renewals-disabled").show();
|
||||
}
|
||||
})
|
||||
.prop("checked", false);
|
||||
}
|
||||
|
||||
if (AllowFineOverrideRenewing) {
|
||||
$("#override_debt")
|
||||
.click(function () {
|
||||
if (this.checked) {
|
||||
$(".renewals-allowed-too_much_owing").show();
|
||||
$(".renewals-allowed-auto_too_much_owing").show();
|
||||
} else {
|
||||
$(".renewals-allowed-too_much_owing").hide();
|
||||
$(".renewals-allowed-auto_too_much_owing").hide();
|
||||
}
|
||||
})
|
||||
.prop("checked", false);
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@ export class CirculationAPIClient {
|
|||
this.httpClient.post({
|
||||
endpoint: "renew",
|
||||
body:
|
||||
"itemnumber=%s&borrowernumber=%s&branchcode=%s&override_limit=%s".format(
|
||||
"itemnumber=%s&borrowernumber=%s&branchcode=%s&override_limit=%s&override_debt=%s".format(
|
||||
checkout.item_id,
|
||||
checkout.patron_id,
|
||||
checkout.library_id,
|
||||
checkout.override_limit
|
||||
checkout.override_limit,
|
||||
checkout.override_debt || 0
|
||||
) +
|
||||
(checkout.seen !== undefined
|
||||
? "&seen=%s".format(checkout.seen)
|
||||
|
|
|
|||
|
|
@ -46,10 +46,12 @@ print $input->header( -type => 'application/json', -charset => 'UTF-8' );
|
|||
my $itemnumber = $input->param('itemnumber');
|
||||
my $borrowernumber = $input->param('borrowernumber');
|
||||
my $override_limit = $input->param('override_limit');
|
||||
my $override_debt = $input->param('override_debt');
|
||||
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') );
|
||||
}
|
||||
|
|
@ -79,6 +81,13 @@ if ( $data->{error} && $data->{error} eq 'too_many' && C4::Context->preference('
|
|||
push @{$confirmations}, 'RENEWAL_LIMIT' if $override_limit;
|
||||
}
|
||||
|
||||
if ( $data->{error} && ( $data->{error} eq 'too_much_owing' or $data->{error} eq 'auto_too_much_owing' ) ) {
|
||||
if ( $override_debt && C4::Context->preference('AllowFineOverrideRenewing') ) {
|
||||
$data->{renew_okay} = 1;
|
||||
$data->{error} = undef;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $data->{renew_okay} || ( $seen && $data->{error} eq 'too_unseen' ) ) {
|
||||
try {
|
||||
$date_due = AddRenewal(
|
||||
|
|
|
|||
|
|
@ -59,9 +59,11 @@ describe("Circulation - FineNoRenewals and AllowFineOverrideRenewing", () => {
|
|||
|
||||
// Should see error message about patron debt
|
||||
cy.get(".dialog.alert").should("be.visible");
|
||||
cy.get(".dialog.alert li").should(
|
||||
cy.get(".dialog.alert").should("contain", "total debt of");
|
||||
cy.get(".dialog.alert").should("contain", "non-issuing charges");
|
||||
cy.get(".dialog.alert").should(
|
||||
"contain",
|
||||
`The patron has a debt of`
|
||||
"Renewals are blocked when non-issuing charges exceed"
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -80,11 +82,8 @@ describe("Circulation - FineNoRenewals and AllowFineOverrideRenewing", () => {
|
|||
|
||||
// Should see error message about patron debt
|
||||
cy.get(".dialog.alert").should("be.visible");
|
||||
|
||||
cy.get(".dialog.alert li").should(
|
||||
"contain",
|
||||
`The patron has a debt of`
|
||||
);
|
||||
cy.get(".dialog.alert").should("contain", "total debt of");
|
||||
cy.get(".dialog.alert").should("contain", "non-issuing charges");
|
||||
|
||||
// Should see override button
|
||||
cy.get('.dialog.alert form button[type="submit"].approve').should(
|
||||
|
|
@ -111,9 +110,11 @@ describe("Circulation - FineNoRenewals and AllowFineOverrideRenewing", () => {
|
|||
|
||||
// Should see error message about patron debt
|
||||
cy.get(".dialog.alert").should("be.visible");
|
||||
cy.get(".dialog.alert li").should(
|
||||
cy.get(".dialog.alert").should("contain", "total debt of");
|
||||
cy.get(".dialog.alert").should("contain", "non-issuing charges");
|
||||
cy.get(".dialog.alert").should(
|
||||
"contain",
|
||||
`The patron has a debt of`
|
||||
"Renewals are blocked when non-issuing charges exceed"
|
||||
);
|
||||
|
||||
// Should NOT see override button
|
||||
|
|
|
|||
Loading…
Reference in New Issue