From 219b10de57cbbafe2546e29e75c05211add00b5f Mon Sep 17 00:00:00 2001 From: Solene Ngamga Date: Wed, 12 Apr 2023 10:35:29 -0400 Subject: [PATCH] Bug 9762: Log circulation overrides This patch allows you to save commands that have been overridden by someone. To test: --After each step, a message will be display on the actionlog-- Circulation -- Checking out - Check out an item that is age restricted (AgeRestrictionOverride syspref) - Check out an item that has a not for loan status (AllowNotForLoanOverride syspref) - Check out an item that has a lost status (IssueLostItem syspref) - Check out an item to a patron who has reached the checkout limit (AllowTooManyOverride syspref) - Check out an item to a patron who is not allowed to borrow this item type - Check out an item to a patron who has unpaid fines (AllFinesNeedOverride and/or AllowFineOverride + noissuescharge sysprefs) - Check out an item on hold for someone else - Check out an item on hold ready for pickup by someone else - Check out an item already checked out to someone else (AutoReturnCheckedOutItems syspref) - Check out to a patron who has restrictions Circulation -- Checking in - Ignore a hold upon check in - Ignore a hold & transfer upon check in Circulation -- Renewing - Renew an item on hold for someone else - Renew an item that has reached the maximum amount of renewals Holds - Place a hold for a patron who is not allowed to put this item type on hold - Place a hold for a patron who has reached the maximum amount of holds - Place an item-level hold when rules say this is not allowed Signed-off-by: Solene Ngamga --- C4/Circulation.pm | 166 ++++++++++++++++++++++++++++++++++---------- circ/circulation.pl | 17 +++++ circ/renew.pl | 22 +++++- circ/returns.pl | 14 +++- reserve/request.pl | 14 ++++ 5 files changed, 194 insertions(+), 39 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 6bba369114..dfb770dd5c 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -318,6 +318,21 @@ A recall for this item was found, and the item needs to be transferred to the re =cut +my $query = CGI->new; + +my $stickyduedate = $query->param('stickyduedate'); +my $duedatespec = $query->param('duedatespec'); +my $restoreduedatespec = $query->param('restoreduedatespec') || $duedatespec; +if ( $restoreduedatespec && $restoreduedatespec eq "highholds_empty" ) { + undef $restoreduedatespec; +} +my $issueconfirmed = $query->param('issueconfirmed'); +my $cancelreserve = $query->param('cancelreserve'); +my $cancel_recall = $query->param('cancel_recall'); +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{}; + sub transferbook { my $params = shift; my $tbr = $params->{to_branch}; @@ -796,9 +811,19 @@ sub CanBookBeIssued { my $circ_library = Koha::Libraries->find( _GetCircControlBranch($item_unblessed, $patron_unblessed) ); my $now = dt_from_string(); + my $message; + $duedate ||= CalcDateDue( $now, $effective_itemtype, $circ_library->branchcode, $patron_unblessed ); if (DateTime->compare($duedate,$now) == -1 ) { # duedate cannot be before now $needsconfirmation{INVALID_DATE} = $duedate; + if ($issueconfirmed) { + if ($message ) { + $message = "$message + sticky due date is invalid or due date in the past"; + } else { + $message = "sticky due date is invalid or due date in the past"; + } + } + } my $fees = Koha::Charges::Fees->new( @@ -906,10 +931,24 @@ sub CanBookBeIssued { else { if ( $non_issues_charges > $amountlimit && $allowfineoverride ) { $needsconfirmation{DEBT} = $non_issues_charges; + if ($issueconfirmed) { + if ($message) { + $message = "$message + guarantees had amend"; + } else { + $message = "guarantees had amend"; + } + } } elsif ( $non_issues_charges > $amountlimit && !$allowfineoverride) { $issuingimpossible{DEBT} = $non_issues_charges; } elsif ( $non_issues_charges > 0 && $allfinesneedoverride ) { $needsconfirmation{DEBT} = $non_issues_charges; + if ($issueconfirmed) { + if ($message) { + $message = "$message + guarantees had amend"; + } else { + $message = "guarantees had amend"; + } + } } } @@ -989,6 +1028,13 @@ sub CanBookBeIssued { } else { if ( C4::Context->preference('AutoReturnCheckedOutItems') ) { $alerts{RETURNED_FROM_ANOTHER} = { patron => $patron }; + if ($issueconfirmed) { + if ($message) { + $message = "$message + Auto Return Checked Out Items"; + } else { + $message = "Auto Return Checked Out Items"; + } + } } else { $needsconfirmation{ISSUED_TO_ANOTHER} = 1; $needsconfirmation{issued_firstname} = $patron->firstname; @@ -1016,6 +1062,14 @@ sub CanBookBeIssued { $needsconfirmation{TOO_MANY} = $toomany->{reason}; $needsconfirmation{current_loan_count} = $toomany->{count}; $needsconfirmation{max_loans_allowed} = $toomany->{max_allowed}; + if ($issueconfirmed) { + if ($message) { + $message = "$message + too many items for the type"; + } else { + $message = "too many items for the type"; + } + + } } else { $issuingimpossible{TOO_MANY} = $toomany->{reason}; $issuingimpossible{current_loan_count} = $toomany->{count}; @@ -1042,6 +1096,13 @@ sub CanBookBeIssued { }else{ $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1; $needsconfirmation{item_notforloan} = $item_object->notforloan; + if ($issueconfirmed) { + if ($message) { + $message = "$message + item not for loan"; + } else { + $message = "item not for loan"; + } + } } } else { @@ -1088,6 +1149,13 @@ sub CanBookBeIssued { my $code = $av->count ? $av->next->lib : ''; $needsconfirmation{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'confirm' ); $alerts{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'alert' ); + if ($issueconfirmed) { + if ($message) { + $message = "$message + Item lost"; + } else { + $message = "Item lost"; + } + } } if ( C4::Context->preference("IndependentBranches") ) { my $userenv = C4::Context->userenv; @@ -1184,6 +1252,13 @@ sub CanBookBeIssued { $needsconfirmation{'resbranchcode'} = $res->{branchcode}; $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'}; $needsconfirmation{'reserve_id'} = $res->{reserve_id}; + if ($issueconfirmed) { + if($message) { + $message = "$message + The item is on reserve and waiting, but has been reserved by some other patron."; + } else { + $message = "The item is on reserve and waiting, but has been reserved by some other patron."; + } + } } elsif ( $restype eq "Reserved" ) { # The item is on reserve for someone else. @@ -1195,6 +1270,13 @@ sub CanBookBeIssued { $needsconfirmation{'resbranchcode'} = $res->{branchcode}; $needsconfirmation{'resreservedate'} = $res->{reservedate}; $needsconfirmation{'reserve_id'} = $res->{reserve_id}; + if ($issueconfirmed) { + if($message) { + $message = "$message + The item is on reserve for someone else"; + } else { + $message = "The item is on reserve for someone else"; + } + } } elsif ( $restype eq "Transferred" ) { # The item is determined hold being transferred for someone else. @@ -1206,6 +1288,13 @@ sub CanBookBeIssued { $needsconfirmation{'resbranchcode'} = $res->{branchcode}; $needsconfirmation{'resreservedate'} = $res->{reservedate}; $needsconfirmation{'reserve_id'} = $res->{reserve_id}; + if ($issueconfirmed) { + if($message) { + $message = "$message + The item is determined hold being transferred for someone else"; + } else { + $message = "The item is determined hold being transferred for someone else"; + } + } } elsif ( $restype eq "Processing" ) { # The item is determined hold being processed for someone else. @@ -1217,6 +1306,13 @@ sub CanBookBeIssued { $needsconfirmation{'resbranchcode'} = $res->{branchcode}; $needsconfirmation{'resreservedate'} = $res->{reservedate}; $needsconfirmation{'reserve_id'} = $res->{reserve_id}; + if ($issueconfirmed) { + if($message) { + $message = "$message + The item is determined hold being processed for someone else"; + } else { + $message = "The item is determined hold being processed for someone else"; + } + } } } } @@ -1228,6 +1324,11 @@ sub CanBookBeIssued { if ( $daysToAgeRestriction && $daysToAgeRestriction > 0 ) { if ( C4::Context->preference('AgeRestrictionOverride') ) { $needsconfirmation{AGE_RESTRICTION} = "$agerestriction"; + if($message) { + $message = "$message + Age restriction"; + } else { + $message = "Age restriction"; + } } else { $issuingimpossible{AGE_RESTRICTION} = "$agerestriction"; @@ -1284,6 +1385,29 @@ sub CanBookBeIssued { } } + my $borrower = $patron; + my $cardnumber = $patron->cardnumber; + my $datestring = localtime(); + my $commis = C4::Context->userenv->{id}; + my $branchcode = C4::Context->userenv->{branch}; + my $item = Koha::Items->find( { barcode => $barcode } ); + my $itemnumber = $item->itemnumber; + + # action, cardnumber, barcode, date, heure, commis, branche + if ($issueconfirmed) { + logaction( + "CIRCULATION", "ISSUE", + $borrower->{'borrowernumber'}, + "$message - $cardnumber - $barcode - $datestring - $commis - $branchcode", + ) if C4::Context->preference("IssueLog"); + } else { + $message = "Circulation"; + logaction( + "CIRCULATION", "ISSUE", + $borrower->{'borrowernumber'}, + "$itemnumber", + ) if C4::Context->preference("IssueLog"); + } return ( \%issuingimpossible, \%needsconfirmation, \%alerts, \%messages, ); } @@ -1742,25 +1866,6 @@ sub AddIssue { } } - my $yaml = C4::Context->preference('UpdateNotForLoanStatusOnCheckout'); - if ($yaml) { - $yaml = "$yaml\n\n"; - - my $rules; - eval { $rules = YAML::XS::Load(Encode::encode_utf8($yaml)); }; - if ($@) { - warn "Unable to parse UpdateNotForLoanStatusOnCheckout syspref : $@"; - } - else { - foreach my $key ( keys %$rules ) { - if ( $item_object->notforloan eq $key ) { - $item_object->notforloan($rules->{$key})->store({ log_action => 0, skip_record_index => 1 }); - last; - } - } - } - } - # Record the fact that this book was issued. C4::Stats::UpdateStats( { @@ -1795,11 +1900,6 @@ sub AddIssue { } ); } - logaction( - "CIRCULATION", "ISSUE", - $borrower->{'borrowernumber'}, - $item_object->itemnumber, - ) if C4::Context->preference("IssueLog"); Koha::Plugins->call('after_circ_action', { action => 'checkout', @@ -2296,8 +2396,7 @@ sub AddReturn { $transfer->receive; $messages->{'TransferArrived'} = $transfer->frombranch; # validTransfer=1 allows us returning the item back if the reserve is cancelled - $validTransfer = 1 - if defined $transfer->reason && $transfer->reason eq 'Reserve'; + $validTransfer = 1 if $transfer->reason eq 'Reserve'; } else { $messages->{'WrongTransfer'} = $transfer->tobranch; @@ -3083,9 +3182,6 @@ fallback to a true value C<$automatic> is a boolean flag indicating the renewal was triggered automatically and not by a person ( librarian or patron ) -C<$skip_record_index> is an optional boolean flag to indicate whether queuing the search indexing -should be skipped for this renewal. - =cut sub AddRenewal { @@ -3097,7 +3193,6 @@ sub AddRenewal { my $skipfinecalc = shift; my $seen = shift; my $automatic = shift; - my $skip_record_index = shift; # Fallback on a 'seen' renewal $seen = defined $seen && $seen == 0 ? 0 : 1; @@ -3192,7 +3287,7 @@ sub AddRenewal { $renews = ( $item_object->renewals || 0 ) + 1; $item_object->renewals($renews); $item_object->onloan($datedue); - # Don't index as we are in a transaction, skip hardcoded here + # Don't index as we are in a transaction $item_object->store({ log_action => 0, skip_record_index => 1 }); # Charge a new rental fee, if applicable @@ -3278,12 +3373,9 @@ sub AddRenewal { } }); }); - - unless( $skip_record_index ){ - # We index now, after the transaction is committed - my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX }); - $indexer->index_records( $item_object->biblionumber, "specialUpdate", "biblioserver" ); - } + # We index now, after the transaction is committed + my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX }); + $indexer->index_records( $item_object->biblionumber, "specialUpdate", "biblioserver" ); return $datedue; } diff --git a/circ/circulation.pl b/circ/circulation.pl index 61065c726d..8ecbca7cce 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -38,6 +38,7 @@ use C4::Members; use C4::Biblio qw( TransformMarcToKoha ); use C4::Search qw( new_record_from_zebra ); use C4::Reserves; +use C4::Log qw( logaction ); use Koha::Holds; use C4::Context; use CGI::Session; @@ -400,9 +401,25 @@ if (@$barcodes) { } ); $recall_id = ( $recall and $recall->id ) ? $recall->id : undef; + } my $issue = AddIssue( $patron->unblessed, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, cancel_recall => $cancel_recall, recall_id => $recall_id, } ); $template_params->{issue} = $issue; + + my $borrower = $patron; + my $cardnumber = $patron->cardnumber; + my $datestring = localtime(); + my $commis = C4::Context->userenv->{id}; + my $branchcode = C4::Context->userenv->{branch}; + $message = "Restriction overridden temporarily"; + + if ($issueconfirmed) { + logaction( + "CIRCULATION", "ISSUE", + $borrower->{'borrowernumber'}, + "$message - $cardnumber - $barcode - $datestring - $commis - $branchcode", + ) if C4::Context->preference("IssueLog"); + } $session->clear('auto_renew'); $inprocess = 1; } diff --git a/circ/renew.pl b/circ/renew.pl index f495a4061f..e6907b097b 100755 --- a/circ/renew.pl +++ b/circ/renew.pl @@ -24,6 +24,7 @@ use C4::Context; use C4::Auth qw( get_template_and_user ); use C4::Output qw( output_html_with_http_headers ); use C4::Circulation qw( barcodedecode CanBookBeRenewed GetLatestAutoRenewDate AddRenewal ); +use C4::Log qw( logaction ); use Koha::DateUtils qw( dt_from_string ); use Koha::Database; use Koha::BiblioFrameworks; @@ -63,7 +64,12 @@ if ($barcode) { if ($issue) { $borrower = $issue->patron(); - + my $cardnumber = $borrower->cardnumber; + my $datestring = localtime(); + my $commis = C4::Context->userenv->{id}; + my $branchcode = C4::Context->userenv->{branch}; + my $message; + if ( ( $borrower->debarred() || q{} ) lt dt_from_string()->ymd() ) { my $can_renew; my $info; @@ -75,6 +81,13 @@ if ($barcode) { if ($override_holds) { $can_renew = 1; $error = undef; + + $message = "Override Renew hold for another"; + logaction( + "CIRCULATION", "RENEWAL", + $borrower->{'borrowernumber'}, + "$message - $cardnumber - $barcode - $datestring - $commis - $branchcode", + ) if C4::Context->preference("RenewalLog"); } else { $can_renew = 0; @@ -108,6 +121,13 @@ if ($barcode) { !$unseen ); $template->param( date_due => $date_due ); + + $message = "Override limit Renew"; + logaction( + "CIRCULATION", "RENEWAL", + $borrower->{'borrowernumber'}, + "$message - $cardnumber - $barcode - $datestring - $commis - $branchcode", + ) if C4::Context->preference("RenewalLog"); } } else { diff --git a/circ/returns.pl b/circ/returns.pl index 08d8cbdc9b..c3925192c7 100755 --- a/circ/returns.pl +++ b/circ/returns.pl @@ -43,6 +43,7 @@ use C4::Members; use C4::Output qw( output_html_with_http_headers ); use C4::Reserves qw( ModReserve ModReserveAffect GetOtherReserves ); use C4::RotatingCollections; +use C4::Log qw( logaction ); use Koha::AuthorisedValues; use Koha::BiblioFrameworks; use Koha::Calendar; @@ -175,6 +176,17 @@ if ( $query->param('reserve_id') ) { diffbranch => 1, ); } +} else { + my $message = "return an element that is reserved"; + my $datestring = localtime(); + my $commis = C4::Context->userenv->{id}; + my $branchcode = C4::Context->userenv->{branch}; + + logaction( + "CIRCULATION", "RETURN", + $session, + "$message - $datestring - $commis - $branchcode", + ) if C4::Context->preference("ReturnLog"); } if ( $query->param('recall_id') ) { @@ -419,7 +431,7 @@ if ($barcode) { } # Mark missing bundle items as lost and report unexpected items - if ( $item && $item->is_bundle && $query->param('confirm_items_bundle_return') && !$query->param('do_not_verify_items_bundle_contents') ) { + if ( $item && $item->is_bundle && $query->param('confirm_items_bundle_return') ) { my $BundleLostValue = C4::Context->preference('BundleLostValue'); my $barcodes = $query->param('verify-items-bundle-contents-barcodes'); my @barcodes = map { s/^\s+|\s+$//gr } ( split /\n/, $barcodes ); diff --git a/reserve/request.pl b/reserve/request.pl index fce3a6e5b0..a9ecf8207d 100755 --- a/reserve/request.pl +++ b/reserve/request.pl @@ -40,6 +40,7 @@ use C4::Serials qw( CountSubscriptionFromBiblionumber ); use C4::Circulation qw( _GetCircControlBranch GetBranchItemRule ); use Koha::DateUtils qw( dt_from_string ); use C4::Search qw( enabled_staff_search_views ); +use C4::Log qw( logaction ); use Koha::Biblios; use Koha::Checkouts; @@ -553,6 +554,19 @@ if ( ( $findborrower && $borrowernumber_hold || $findclub && $club_hold ) } } else { $num_alreadyheld++ } + my $borrower = $patron; + my $cardnumber = $patron->cardnumber; + my $datestring = localtime(); + my $commis = C4::Context->userenv->{id}; + my $branchcode = C4::Context->userenv->{branch}; + my $message = "Override limitation of hold"; + + logaction( + "HOLD", "ISSUE", + $borrower->{'borrowernumber'}, + "$message - $cardnumber - $datestring - $commis - $branchcode", + ) if C4::Context->preference("IssueLog"); + push( @available_itemtypes, $item->{itype} ); } else { # If none of the conditions hold true, then neither override nor available is set and the item cannot be checked -- 2.34.1