From 2a620e644ea7b843c5367448883279ab15e86045 Mon Sep 17 00:00:00 2001 From: Jacob O'Mara Date: Thu, 6 Feb 2025 12:22:06 +0000 Subject: [PATCH] Bug 38924: Add quota picker to checkout confirmation This patch adds the quota selector to the checkout confirmation for if multiple eligable quotas are available Bug 38924: Return all eligable quotas so that the staff user can pick This patch adds the logic to return multiple eligable quotas if there are more than 1, allowing the staff user to pick which to assign an item to. Bug 38924: Add searcher method for currently active quota for patron Bug 38924: amend circ logic to handle multiple eligable quotas This amends the circulations logic to handle the fact that we can return multiple eligable quotas now. This ensures that the same quotas as was used for the checkout will be used for the renewal (both check and assignment) and that we use the selected quota from our confirmation dropdown for checkout of new item Bug 38924: add better name display for quota select at checkout --- C4/Circulation.pm | 51 ++++++++---- Koha/Patron/Quotas.pm | 80 +++++++++++++------ circ/circulation.pl | 3 +- .../prog/en/modules/circ/circulation.tt | 23 +++++- 4 files changed, 115 insertions(+), 42 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 8f53423e700..5b9bc435d73 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -67,6 +67,7 @@ use Koha::Library::Hours; use Koha::Patron::Quotas; use Koha::Patron::Quota; use Koha::Patron::Quota::Usage; +use Koha::Patron::Quota::Usages; use Carp qw( carp ); use List::MoreUtils qw( any ); @@ -1356,11 +1357,15 @@ sub CanBookBeIssued { # CHECK FOR QUOTAS if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) { - unless ( $quota->has_available_quota ) { + if (ref($quota) eq 'ARRAY') { + # Multiple available quotas found - need confirmation from user + $needsconfirmation{QUOTA_SELECT} = $quota; + } + elsif (!$quota->has_available_quota) { if ( C4::Context->preference("AllowQuotaOverride") ) { $needsconfirmation{QUOTA_EXCEEDED} = { available => $quota->available_quota, - total => $quota->allocation, + total => $quota->allocation, used => $quota->used, }; } @@ -1599,6 +1604,7 @@ sub AddIssue { my $auto_renew = $params && $params->{auto_renew}; my $cancel_recall = $params && $params->{cancel_recall}; my $recall_id = $params && $params->{recall_id}; + my $selected_quota_id = $params && $params->{selected_quota_id}; my $dbh = C4::Context->dbh; my $barcodecheck = CheckValidBarcode($barcode); @@ -1925,9 +1931,16 @@ sub AddIssue { if C4::Context->preference('RealTimeHoldsQueue'); # Check quotas and record usage if needed - if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) { - # Update patron's used quota value - $quota->add_usage({ + my $quota; + if ($selected_quota_id) { + $quota = Koha::Patron::Quotas->find($selected_quota_id); + } else { + $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber); + } + + if ($quota) { + # Update patron's used quota value + $quota->add_usage({ patron_id => $patron->patron_id, issue_id => $issue->issue_id, }); @@ -3269,10 +3282,15 @@ sub CanBookBeRenewed { } } - # CHECK FOR QUOTAS - if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) { - unless ( $quota->has_available_quota ) { - return ( 0, "QUOTA_EXCEEDED" ); + # # CHECK FOR QUOTAS + if (my $quota_usage = Koha::Patron::Quota::Usages->find({ issue_id => $issue->issue_id })) { + + # Get current active quota for the patron + if (my $active_quota = Koha::Patron::Quotas->get_active_quota($quota_usage->patron_id)) { + + if (!$active_quota->has_available_quota) { + return (0, "QUOTA_EXCEEDED"); + } } } @@ -3389,12 +3407,15 @@ sub AddRenewal { my $circ_library = Koha::Libraries->find( _GetCircControlBranch( $item_object, $patron ) ); # Check quotas and record usage if needed - if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) { - # Update patron's used quota value - $quota->add_usage({ - patron_id => $patron->patron_id, - issue_id => $issue->issue_id, - }); + if (my $quota_usage = Koha::Patron::Quota::Usages->find({ issue_id => $issue->issue_id })) { + # Get current active quota for the patron + if (my $active_quota = Koha::Patron::Quotas->get_active_quota($quota_usage->patron_id)) { + # Update patron's used quota value + $active_quota->add_usage({ + patron_id => $patron->patron_id, + issue_id => $issue->issue_id, + }); + } } my $schema = Koha::Database->schema; diff --git a/Koha/Patron/Quotas.pm b/Koha/Patron/Quotas.pm index 8f31767999e..c8e2715a86b 100644 --- a/Koha/Patron/Quotas.pm +++ b/Koha/Patron/Quotas.pm @@ -1,9 +1,9 @@ package Koha::Patron::Quotas; +use base qw(Koha::Objects); use Modern::Perl; use Koha::Patron::Quota; use Koha::Patrons; -use base qw(Koha::Objects); =head1 NAME @@ -25,47 +25,57 @@ Searches for any applicable quota for the given patron. Returns: =cut sub get_patron_quota { - my ($self, $patron_id) = @_; - - my $patron_quota = undef; + my ( $self, $patron_id ) = @_; + + my @available_quotas; my $first_found_quota = undef; - # First check all guarantor quotas if enabled - if (C4::Context->preference('UseGuarantorQuota')) { - my $patron = Koha::Patrons->find($patron_id); + # First check patron's own quota + my $patron_quota = $self->search( + { + patron_id => $patron_id, + start_date => { '<=' => \'CURRENT_DATE' }, + end_date => { '>=' => \'CURRENT_DATE' } + } + )->single; + + if ( $patron_quota && $patron_quota->has_available_quota ) { + push @available_quotas, $patron_quota; + } + $first_found_quota ||= $patron_quota if $patron_quota; + + # Then check all guarantor quotas if enabled + if ( C4::Context->preference('UseGuarantorQuota') ) { + my $patron = Koha::Patrons->find($patron_id); my @guarantors = $patron->guarantor_relationships->guarantors->as_list; foreach my $guarantor (@guarantors) { my $guarantor_quota = $self->search( { - patron_id => $guarantor->borrowernumber, + patron_id => $guarantor->borrowernumber, start_date => { '<=' => \'CURRENT_DATE' }, end_date => { '>=' => \'CURRENT_DATE' } } )->single; if ($guarantor_quota) { - # Return immediately if guarantor quota has availability - if ($guarantor_quota->has_available_quota) { - return $guarantor_quota; - } + # Store first found quota in case we need it later $first_found_quota ||= $guarantor_quota; + + # Collect available guarantor quotas + if ( $guarantor_quota->has_available_quota ) { + push @available_quotas, $guarantor_quota; + } } } } - # Check patron's own quota if no available guarantor quota was found - $patron_quota = $self->search( - { - patron_id => $patron_id, - start_date => { '<=' => \'CURRENT_DATE' }, - end_date => { '>=' => \'CURRENT_DATE' } - } - )->single; - - # Return patron quota if exists, otherwise first found guarantor quota - return $patron_quota || $first_found_quota; + # Return single quota if only one available, array of quotas if multiple available, + # first found quota if none available + return $available_quotas[0] if @available_quotas == 1; + return \@available_quotas if @available_quotas > 1; + return $first_found_quota; } =head3 create_quota @@ -107,6 +117,28 @@ sub get_active_quotas { ); } +=head2 get_active_quota + + my $active_quota = Koha::Patron::Quotas->get_active_quota($patron_id); + +Returns the currently active quota for a patron if one exists. +Active means start_date <= NOW() and end_date >= NOW(). +Returns undef if no active quota found. + +=cut + +sub get_active_quota { + my ( $self, $patron_id ) = @_; + + return Koha::Patron::Quotas->search( + { + patron_id => $patron_id, + start_date => { '<=' => \'CURRENT_DATE' }, + end_date => { '>=' => \'CURRENT_DATE' } + } + )->single; +} + =head2 Internal methods =head3 _type @@ -119,7 +151,7 @@ sub _type { =head3 object_class -Returns the package name for patron quota objects +Returns the package name for koha patron quota objects =cut diff --git a/circ/circulation.pl b/circ/circulation.pl index 75dc2670418..6e62a6bdeb8 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -186,6 +186,7 @@ if ( $restoreduedatespec && $restoreduedatespec eq "highholds_empty" ) { my $issueconfirmed = $query->param('issueconfirmed'); my $cancelreserve = $query->param('cancelreserve'); my $cancel_recall = $query->param('cancel_recall'); +my $selected_quota_id = $query->param('selected_quota_id'); my $recall_id = $query->param('recall_id'); my $debt_confirmed = $query->param('debt_confirmed') || 0; # Don't show the debt error dialog twice my $charges = $query->param('charges') || q{}; @@ -543,7 +544,7 @@ if ( @$barcodes && $op eq 'cud-checkout' ) { { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, cancel_recall => $cancel_recall, - recall_id => $recall_id, + recall_id => $recall_id, selected_quota_id => $selected_quota_id, } ); $template_params->{issue} = $issue; 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 06b8af85305..30d321b9b3a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -137,7 +137,7 @@ [%IF ( QUOTA_EXCEEDED ) %]
  • - Quota Exceeded [% QUOTA_EXCEEDED | html %]. + Quota Exceeded. Available: [% QUOTA_EXCEEDED.available | html %] / [% QUOTA_EXCEEDED.total | html %]. [% IF CAN_user_circulate_force_checkout %] Check out anyway? [% END %] @@ -377,6 +377,25 @@ [% END %] [% END %] + [% IF ( QUOTA_SELECT ) %] +

    + + +

    + [% END %] + @@ -638,7 +657,7 @@ [% END %] [%IF ( QUOTA_EXCEEDED ) %] -
  • Quota Exceeded [% QUOTA_EXCEEDED | html %].
  • +
  • Quota Exceeded. Available: [% QUOTA_EXCEEDED.available | html %] / [% QUOTA_EXCEEDED.total | html %].
  • [% END %] [% IF ( EXPIRED ) %] -- 2.48.1