use Koha::Illrequests;
use Koha::Items;
use Koha::Patrons;
-use Koha::Patron::Debarments qw( DelUniqueDebarment GetDebarments AddUniqueDebarment );
+use Koha::Patron::Debarments qw( DelUniqueDebarment AddUniqueDebarment );
use Koha::Database;
use Koha::Libraries;
use Koha::Account::Lines;
} elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') {
$checkouts = $patron->checkouts; # if branch is the patron's home branch, then count all loans by patron
} else {
+ my $branch_type = C4::Context->preference('HomeOrHoldingBranch') || 'homebranch';
$checkouts = $patron->checkouts->search(
- { 'item.homebranch' => $maxissueqty_rule->branchcode } );
+ { "item.$branch_type" => $maxissueqty_rule->branchcode } );
}
} else {
$checkouts = $patron->checkouts; # if rule is not branch specific then count all loans by patron
} elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') {
$checkouts = $patron->checkouts; # if branch is the patron's home branch, then count all loans by patron
} else {
+ my $branch_type = C4::Context->preference('HomeOrHoldingBranch') || 'homebranch';
$checkouts = $patron->checkouts->search(
- { 'item.homebranch' => $branch},
- { prefetch => 'item' } );
+ { "item.$branch_type" => $branch},
+ { prefetch => 'item' } );
}
my $checkout_count = $checkouts->count;
$needsconfirmation{'ressurname'} = $patron->surname;
$needsconfirmation{'rescardnumber'} = $patron->cardnumber;
$needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
- $needsconfirmation{'resbranchcode'} = $patron->branchcode;
+ $needsconfirmation{'resbranchcode'} = $res->{branchcode};
$needsconfirmation{'resreservedate'} = $res->{reservedate};
$needsconfirmation{'reserve_id'} = $res->{reserve_id};
}
$needsconfirmation{'ressurname'} = $patron->surname;
$needsconfirmation{'rescardnumber'} = $patron->cardnumber;
$needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
- $needsconfirmation{'resbranchcode'} = $patron->branchcode;
+ $needsconfirmation{'resbranchcode'} = $res->{branchcode};
$needsconfirmation{'resreservedate'} = $res->{reservedate};
$needsconfirmation{'reserve_id'} = $res->{reserve_id};
}
$needsconfirmation{'ressurname'} = $patron->surname;
$needsconfirmation{'rescardnumber'} = $patron->cardnumber;
$needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
- $needsconfirmation{'resbranchcode'} = $patron->branchcode;
+ $needsconfirmation{'resbranchcode'} = $res->{branchcode};
$needsconfirmation{'resreservedate'} = $res->{reservedate};
$needsconfirmation{'reserve_id'} = $res->{reserve_id};
}
due_date => undef,
};
- my $holds = Koha::Holds->search( { biblionumber => $item->biblionumber } );
+
+ # Count holds on this record, ignoring the borrowers own holds as they would be filled by the checkout
+ my $holds = Koha::Holds->search({
+ biblionumber => $item->biblionumber,
+ borrowernumber => { '!=' => $patron->borrowernumber }
+ });
if ( $holds->count() ) {
$return_data->{outstanding} = $holds->count();
# static means just more than a given number of holds on the record
- # If the number of holds is less than the threshold, we can stop here
- if ( $holds->count() < $decreaseLoanHighHoldsValue ) {
+ # If the number of holds is not above the threshold, we can stop here
+ if ( $holds->count() <= $decreaseLoanHighHoldsValue ) {
return $return_data;
}
}
}
# Remove any items that are not holdable for this patron
- @items = grep { CanItemBeReserved( $patron , $_, undef, { ignore_found_holds => 1 } )->{status} eq 'OK' } @items;
+ # We need to ignore hold counts as the borrower's own hold that will be filled by the checkout
+ # could prevent them from placing further holds
+ @items = grep { CanItemBeReserved( $patron, $_, undef, { ignore_hold_counts => 1 } )->{status} eq 'OK' } @items;
my $items_count = scalar @items;
);
}
else {
+
unless ($datedue) {
my $itype = $item_object->effective_itemtype;
$datedue = CalcDateDue( $issuedate, $itype, $branchcode, $borrower );
from_any_library: Holds allowed from any patron.
from_local_hold_group: Holds allowed from libraries in hold group
-returnbranch => branch to which to return item. Possible values:
- noreturn: do not return, let item remain where checked in (floating collections)
- homebranch: return to item's home branch
- holdingbranch: return to issuer branch
-
This searches branchitemrules in the following order:
* Same branchcode and itemtype
my $rules = Koha::CirculationRules->get_effective_rules({
branchcode => $branchcode,
itemtype => $itemtype,
- rules => ['holdallowed', 'hold_fulfillment_policy', 'returnbranch']
+ rules => ['holdallowed', 'hold_fulfillment_policy']
});
# built-in default circulation rule
$rules->{holdallowed} //= 'from_any_library';
$rules->{hold_fulfillment_policy} //= 'any';
- $rules->{returnbranch} //= 'homebranch';
return $rules;
}
}
}
+ if ( $item->withdrawn ) { # book has been cancelled
+ $messages->{'withdrawn'} = 1;
+
+ # In the case where we block return of withdrawn, we should completely block the return
+ # without updating item statuses, so we exit early
+ return ( 0, $messages, $issue, ( $patron ? $patron->unblessed : {} ))
+ if C4::Context->preference("BlockReturnOfWithdrawnItems");
+ }
+
+
# full item data, but no borrowernumber or checkout info (no issue)
- my $hbr = GetBranchItemRule($item->homebranch, $itemtype)->{'returnbranch'} || "homebranch";
+ my $hbr = Koha::CirculationRules->get_return_branch_policy($item);
# get the proper branch to which to return the item
my $returnbranch = $hbr ne 'noreturn' ? $item->$hbr : $branch;
# if $hbr was "noreturn" or any other non-item table value, then it should 'float' (i.e. stay at this branch)
foreach my $key ( keys %$rules ) {
if ( $item->notforloan eq $key ) {
$messages->{'NotForLoanStatusUpdated'} = { from => $item->notforloan, to => $rules->{$key} };
- $item->notforloan($rules->{$key})->store({ log_action => 0, skip_record_index => 1, skip_holds_queue => 1 });
+ $item->notforloan($rules->{$key})->store({ log_action => 0, skip_record_index => 1, skip_holds_queue => 1 }) unless $rules->{$key} eq 'ONLYMESSAGE';
last;
}
}
return ( $doreturn, $messages, $issue, $patron_unblessed);
}
- if ( $item->withdrawn ) { # book has been cancelled
- $messages->{'withdrawn'} = 1;
- $doreturn = 0 if C4::Context->preference("BlockReturnOfWithdrawnItems");
- }
-
if ( $item->itemlost and C4::Context->preference("BlockReturnOfLostItems") ) {
$doreturn = 0;
}
for my $message (@object_messages) {
$messages->{'LostItemFeeRefunded'} = 1
if $message->message eq 'lost_refunded';
+ $messages->{'ProcessingFeeRefunded'} = 1
+ if $message->message eq 'processing_refunded';
$messages->{'LostItemFeeRestored'} = 1
if $message->message eq 'lost_restored';
if ( $issue and $issue->is_overdue($return_date) ) {
# fix fine days
my ($debardate,$reminder) = _debar_user_on_return( $patron_unblessed, $item->unblessed, dt_from_string($issue->date_due), $return_date );
- if ($reminder){
- $messages->{'PrevDebarred'} = $debardate;
- } else {
- $messages->{'Debarred'} = $debardate if $debardate;
+ if ($debardate and $debardate ne "9999-12-31") {
+ if ($reminder){
+ $messages->{'PrevDebarred'} = $debardate;
+ } else {
+ $messages->{'Debarred'} = $debardate;
+ }
+ } elsif ($patron->debarred) {
+ if ( $patron->debarred eq "9999-12-31") {
+ $messages->{'ForeverDebarred'} = $patron->debarred;
+ } else {
+ my $borrower_debar_dt = dt_from_string( $patron->debarred );
+ $borrower_debar_dt->truncate(to => 'day');
+ my $today_dt = $return_date->clone()->truncate(to => 'day');
+ if ( DateTime->compare( $borrower_debar_dt, $today_dt ) != -1 ) {
+ $messages->{'PrevDebarred'} = $patron->debarred;
+ }
+ }
}
# there's no overdue on the item but borrower had been previously debarred
} elsif ( $issue->date_due and $patron->debarred ) {
}
# Record the fact that this book was returned.
+ my $categorycode = $patron_unblessed ? $patron_unblessed->{categorycode} : undef;
C4::Stats::UpdateStats({
branch => $branch,
type => $stat_type,
location => $item->location,
borrowernumber => $borrowernumber,
ccode => $item->ccode,
- categorycode => $patron->categorycode,
+ categorycode => $categorycode,
});
# Send a check-in slip. # NOTE: borrower may be undef. Do not try to send messages then.
}
# Remove any OVERDUES related debarment if the borrower has no overdues
+ my $overdue_restrictions = $patron->restrictions->search({ type => 'OVERDUES' });
if ( C4::Context->preference('AutoRemoveOverduesRestrictions')
&& $patron->debarred
&& !$patron->has_overdues
- && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
+ && $overdue_restrictions->count
) {
DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
}
my ( $has_been_extended );
if ( C4::Context->preference('CumulativeRestrictionPeriods') and $borrower->{debarred} ) {
- my $debarment = @{ GetDebarments( { borrowernumber => $borrower->{borrowernumber}, type => 'SUSPENSION' } ) }[0];
+ my $patron = Koha::Patrons->find($borrower->{borrowernumber});
+ my $debarment = $patron->restrictions->search({type => 'SUSPENSION' },{rows => 1})->single;
if ( $debarment ) {
- $return_date = dt_from_string( $debarment->{expiration}, 'sql' );
+ $return_date = dt_from_string( $debarment->expiration, 'sql' );
$has_been_extended = 1;
}
}
my $item = Koha::Items->find($itemnumber) or return ( 0, 'no_item' );
my $issue = $item->checkout or return ( 0, 'no_checkout' );
return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
- return ( 0, 'item_denied_renewal') if _item_denied_renewal({ item => $item });
+ return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
my $patron = $issue->patron or return;
}
return ( 0, $auto_renew, { soonest_renew_date => $soonest } ) if $auto_renew =~ 'too_soon';#$auto_renew ne "no" && $auto_renew ne "ok";
- $soonest = GetSoonestRenewDate($borrowernumber, $itemnumber);
+ $soonest = GetSoonestRenewDate($issue);
if ( $soonest > dt_from_string() ){
return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
}
=head2 AddRenewal
- &AddRenewal($borrowernumber, $itemnumber, $branch, [$datedue], [$lastreneweddate], [$seen]);
+ &AddRenewal($borrowernumber, $itemnumber, $branch, [$datedue], [$lastreneweddate], [$seen], [$automatic]);
Renews a loan.
informs the incrementing of the unseen_renewals column. If this flag is not supplied, we
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 )
+
=cut
sub AddRenewal {
my $lastreneweddate = shift || dt_from_string();
my $skipfinecalc = shift;
my $seen = shift;
+ my $automatic = shift;
# Fallback on a 'seen' renewal
$seen = defined $seen && $seen == 0 ? 0 : 1;
my $issue = $item_object->checkout;
my $item_unblessed = $item_object->unblessed;
+ my $renewal_type = $automatic ? "Automatic" : "Manual";
+
my $dbh = C4::Context->dbh;
return unless $issue;
}
# Remove any OVERDUES related debarment if the borrower has no overdues
+ my $overdue_restrictions = $patron->restrictions->search({ type => 'OVERDUES' });
if ( $patron
&& $patron->is_debarred
&& ! $patron->has_overdues
- && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
+ && $overdue_restrictions->count
) {
DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
}
# Add renewal record
my $renewal = Koha::Checkouts::Renewal->new(
{
- checkout_id => $issue->issue_id,
- renewer_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
- seen => $seen,
- interface => C4::Context->interface
+ checkout_id => $issue->issue_id,
+ interface => C4::Context->interface,
+ renewal_type => $renewal_type,
+ renewer_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
+ seen => $seen,
}
)->store();
=head2 GetSoonestRenewDate
- $NoRenewalBeforeThisDate = &GetSoonestRenewDate($borrowernumber, $itemnumber);
+ $NoRenewalBeforeThisDate = &GetSoonestRenewDate($checkout);
Find out the soonest possible renew date of a borrowed item.
-C<$borrowernumber> is the borrower number of the patron who currently
-has the item on loan.
-
-C<$itemnumber> is the number of the item to renew.
+C<$checkout> is the checkout object to renew.
C<$GetSoonestRenewDate> returns the DateTime of the soonest possible
renew date, based on the value "No renewal before" of the applicable
issuing rule. Returns the current date if the item can already be
-renewed, and returns undefined if the borrower, loan, or item
+renewed, and returns undefined if the patron, item, or checkout
cannot be found.
=cut
sub GetSoonestRenewDate {
- my ( $borrowernumber, $itemnumber ) = @_;
+ my ( $checkout ) = @_;
- my $dbh = C4::Context->dbh;
-
- my $item = Koha::Items->find($itemnumber) or return;
- my $itemissue = $item->checkout or return;
-
- $borrowernumber ||= $itemissue->borrowernumber;
- my $patron = Koha::Patrons->find( $borrowernumber )
- or return;
+ my $item = $checkout->item or return;
+ my $patron = $checkout->patron or return;
my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
my $issuing_rule = Koha::CirculationRules->get_effective_rules(
and $issuing_rule->{norenewalbefore} ne "" )
{
my $soonestrenewal =
- dt_from_string( $itemissue->date_due )->subtract(
+ dt_from_string( $checkout->date_due )->subtract(
$issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
$soonestrenewal->truncate( to => 'day' );
}
return $soonestrenewal if $now < $soonestrenewal;
- } elsif ( $itemissue->auto_renew && $patron->autorenew_checkouts ) {
+ } elsif ( $checkout->auto_renew && $patron->autorenew_checkouts ) {
# Checkouts with auto-renewing fall back to due date
- my $soonestrenewal = dt_from_string( $itemissue->date_due );
+ my $soonestrenewal = dt_from_string( $checkout->date_due );
if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
and $issuing_rule->{lengthunit} eq 'days' )
{
# we only need to calculate and change the fines if we want to do that on return
# Should be on for hourly loans
my $control = C4::Context->preference('CircControl');
+ my $branch_type = C4::Context->preference('HomeOrHoldingBranch') || 'homebranch';
my $control_branchcode =
- ( $control eq 'ItemHomeLibrary' ) ? $item->{homebranch}
+ ( $control eq 'ItemHomeLibrary' ) ? $item->{$branch_type}
: ( $control eq 'PatronLibrary' ) ? $borrower->{branchcode}
: $issue->branchcode;
}
}
- my $soonest = GetSoonestRenewDate($patron->id, $item->id);
+ my $soonest = GetSoonestRenewDate($issue);
if ( $soonest > dt_from_string() )
{
return ( "auto_too_soon", $soonest );
return "ok";
}
-sub _item_denied_renewal {
- my ($params) = @_;
-
- my $item = $params->{item};
- return unless $item;
-
- my $denyingrules = Koha::Config::SysPrefs->find('ItemsDeniedRenewal')->get_yaml_pref_hash();
- return unless $denyingrules;
- foreach my $field (keys %$denyingrules) {
- my $val = $item->$field;
- if( !defined $val) {
- if ( any { !defined $_ } @{$denyingrules->{$field}} ){
- return 1;
- }
- } elsif (any { defined($_) && $val eq $_ } @{$denyingrules->{$field}}) {
- # If the results matches the values in the syspref
- # We return true if match found
- return 1;
- }
- }
- return 0;
-}
1;