&GetBiblioIssues
&GetOpenIssue
&AnonymiseIssueHistory
+ &CheckIfIssuedToPatron
);
# subs to deal with returns
#
# DEBTS
- my ($amount) =
- C4::Members::GetMemberAccountRecords( $borrower->{'borrowernumber'}, '' && $duedate->ymd() );
+ my ($balance, $non_issue_charges, $other_charges) =
+ C4::Members::GetMemberAccountBalance( $borrower->{'borrowernumber'} );
my $amountlimit = C4::Context->preference("noissuescharge");
my $allowfineoverride = C4::Context->preference("AllowFineOverride");
my $allfinesneedoverride = C4::Context->preference("AllFinesNeedOverride");
if ( C4::Context->preference("IssuingInProcess") ) {
- if ( $amount > $amountlimit && !$inprocess && !$allowfineoverride) {
- $issuingimpossible{DEBT} = sprintf( "%.2f", $amount );
- } elsif ( $amount > $amountlimit && !$inprocess && $allowfineoverride) {
- $needsconfirmation{DEBT} = sprintf( "%.2f", $amount );
- } elsif ( $allfinesneedoverride && $amount > 0 && $amount <= $amountlimit && !$inprocess ) {
- $needsconfirmation{DEBT} = sprintf( "%.2f", $amount );
+ if ( $non_issue_charges > $amountlimit && !$inprocess && !$allowfineoverride) {
+ $issuingimpossible{DEBT} = sprintf( "%.2f", $non_issue_charges );
+ } elsif ( $non_issue_charges > $amountlimit && !$inprocess && $allowfineoverride) {
+ $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
+ } elsif ( $allfinesneedoverride && $non_issue_charges > 0 && $non_issue_charges <= $amountlimit && !$inprocess ) {
+ $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
}
}
else {
- if ( $amount > $amountlimit && $allowfineoverride ) {
- $needsconfirmation{DEBT} = sprintf( "%.2f", $amount );
- } elsif ( $amount > $amountlimit && !$allowfineoverride) {
- $issuingimpossible{DEBT} = sprintf( "%.2f", $amount );
- } elsif ( $amount > 0 && $allfinesneedoverride ) {
- $needsconfirmation{DEBT} = sprintf( "%.2f", $amount );
+ if ( $non_issue_charges > $amountlimit && $allowfineoverride ) {
+ $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
+ } elsif ( $non_issue_charges > $amountlimit && !$allowfineoverride) {
+ $issuingimpossible{DEBT} = sprintf( "%.2f", $non_issue_charges );
+ } elsif ( $non_issue_charges > 0 && $allfinesneedoverride ) {
+ $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges );
}
}
+ if ($balance > 0 && $other_charges > 0) {
+ $alerts{OTHER_CHARGES} = sprintf( "%.2f", $other_charges );
+ }
my ($blocktype, $count) = C4::Members::IsMemberBlocked($borrower->{'borrowernumber'});
if ($blocktype == -1) {
#
# ITEM CHECKING
#
- if ( $item->{'notforloan'}
- && $item->{'notforloan'} > 0 )
+ if ( $item->{'notforloan'} )
{
if(!C4::Context->preference("AllowNotForLoanOverride")){
$issuingimpossible{NOT_FOR_LOAN} = 1;
$needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
}
}
- elsif ( !$item->{'notforloan'} ){
+ else {
# we have to check itemtypes.notforloan also
if (C4::Context->preference('item-level_itypes')){
# this should probably be a subroutine
}
}
}
+
+## check for high holds decreasing loan period
+ my $decrease_loan = C4::Context->preference('decreaseLoanHighHolds');
+ if ( $decrease_loan && $decrease_loan == 1 ) {
+ my ( $reserved, $num, $duration, $returndate ) =
+ checkHighHolds( $item, $borrower );
+
+ if ( $num >= C4::Context->preference('decreaseLoanHighHoldsValue') ) {
+ $needsconfirmation{HIGHHOLDS} = {
+ num_holds => $num,
+ duration => $duration,
+ returndate => output_pref($returndate),
+ };
+ }
+ }
+
return ( \%issuingimpossible, \%needsconfirmation, \%alerts );
}
=item C<$message> is the branchcode where the item SHOULD be returned, if the return is not allowed
+=back
+
=cut
sub CanBookBeReturned {
return ($allowed, $message);
}
+=head2 CheckHighHolds
+
+ used when syspref decreaseLoanHighHolds is active. Returns 1 or 0 to define whether the minimum value held in
+ decreaseLoanHighHoldsValue is exceeded, the total number of outstanding holds, the number of days the loan
+ has been decreased to (held in syspref decreaseLoanHighHoldsValue), and the new due date
+
+=cut
+
+sub checkHighHolds {
+ my ( $item, $borrower ) = @_;
+ my $biblio = GetBiblioFromItemNumber( $item->{itemnumber} );
+ my $branch = _GetCircControlBranch( $item, $borrower );
+ my $dbh = C4::Context->dbh;
+ my $sth = $dbh->prepare(
+'select count(borrowernumber) as num_holds from reserves where biblionumber=?'
+ );
+ $sth->execute( $item->{'biblionumber'} );
+ my ($holds) = $sth->fetchrow_array;
+ if ($holds) {
+ my $issuedate = DateTime->now( time_zone => C4::Context->tz() );
+
+ my $calendar = Koha::Calendar->new( branchcode => $branch );
+
+ my $itype =
+ ( C4::Context->preference('item-level_itypes') )
+ ? $biblio->{'itype'}
+ : $biblio->{'itemtype'};
+ my $orig_due =
+ C4::Circulation::CalcDateDue( $issuedate, $itype, $branch,
+ $borrower );
+
+ my $reduced_datedue =
+ $calendar->addDate( $issuedate,
+ C4::Context->preference('decreaseLoanHighHoldsDuration') );
+
+ if ( DateTime->compare( $reduced_datedue, $orig_due ) == -1 ) {
+ return ( 1, $holds,
+ C4::Context->preference('decreaseLoanHighHoldsDuration'),
+ $reduced_datedue );
+ }
+ }
+ return ( 0, 0, 0, undef );
+}
+
=head2 AddIssue
&AddIssue($borrower, $barcode, [$datedue], [$cancelreserve], [$issuedate])
}
if ($borrower and $barcode and $barcodecheck ne '0'){#??? wtf
# find which item we issue
- my $item = GetItem('', $barcode) or return undef; # if we don't get an Item, abort.
+ my $item = GetItem('', $barcode) or return; # if we don't get an Item, abort.
my $branch = _GetCircControlBranch($item,$borrower);
# get actual issuing if there is one
## If item was lost, it has now been found, reverse any list item charges if neccessary.
if ( $item->{'itemlost'} ) {
- _FixAccountForLostAndReturned( $item->{'itemnumber'}, undef, $item->{'barcode'} );
+ if ( C4::Context->preference('RefundLostItemFeeOnReturn' ) ) {
+ _FixAccountForLostAndReturned( $item->{'itemnumber'}, undef, $item->{'barcode'} );
+ }
}
ModItem({ issues => $item->{'issues'},
return $irule if defined($irule) ;
# if no rule matches,
- return undef;
+ return;
}
=head2 GetBranchBorrowerCircRule
if ( $item->{'wthdrawn'} ) { # book has been cancelled
$messages->{'wthdrawn'} = 1;
- $doreturn = 0;
+ $doreturn = 0 if C4::Context->preference("BlockReturnOfWithdrawnItems");
}
# case of a return of document (deal with issues and holdingbranch)
}
# fix up the accounts.....
- if ($item->{'itemlost'}) {
- _FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode); # can tolerate undef $borrowernumber
+ if ( $item->{'itemlost'} ) {
$messages->{'WasLost'} = 1;
+
+ if ( C4::Context->preference('RefundLostItemFeeOnReturn' ) ) {
+ _FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode); # can tolerate undef $borrowernumber
+ $messages->{'LostItemFeeRefunded'} = 1;
+ }
}
# fix up the overdues in accounts...
# find reserves.....
# if we don't have a reserve with the status W, we launch the Checkreserves routine
- my ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->{'itemnumber'} );
+ my ($resfound, $resrec);
+ ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->{'itemnumber'} ) unless ( $item->{'wthdrawn'} );
if ($resfound) {
$resrec->{'ResFound'} = $resfound;
$messages->{'ResFound'} = $resrec;
# $deltadays is a DateTime::Duration object
my $deltadays = $calendar->days_between( $dt_due, $dt_today );
- my $circcontrol = C4::Context::preference('CircControl');
+ my $circcontrol = C4::Context->preference('CircControl');
my $issuingrule =
GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode );
my $finedays = $issuingrule->{finedays};
sub GetBiblioIssues {
my $biblionumber = shift;
- return undef unless $biblionumber;
+ return unless $biblionumber;
my $dbh = C4::Context->dbh;
my $query = "
SELECT issues.*,items.barcode,biblio.biblionumber,biblio.title, biblio.author,borrowers.cardnumber,borrowers.surname,borrowers.firstname
$error="too_many";
}
- my ( $resfound, $resrec, undef ) = C4::Reserves::CheckReserves($itemnumber);
- if ($resfound) {
+ my $resstatus = C4::Reserves::GetReserveStatus($itemnumber);
+ if ( $resstatus eq "Waiting" or $resstatus eq "Reserved" ) {
$renewokay = 0;
- $error="on_reserve"
+ $error->{message} = "on_reserve";
}
-
}
return ($renewokay,$error);
}
=cut
sub AddRenewal {
- my $borrowernumber = shift or return undef;
- my $itemnumber = shift or return undef;
+ my $borrowernumber = shift or return;
+ my $itemnumber = shift or return;
my $branch = shift;
my $datedue = shift;
my $lastreneweddate = shift || DateTime->now(time_zone => C4::Context->tz)->ymd();
- my $item = GetItem($itemnumber) or return undef;
- my $biblio = GetBiblioFromItemNumber($itemnumber) or return undef;
+ my $item = GetItem($itemnumber) or return;
+ my $biblio = GetBiblioFromItemNumber($itemnumber) or return;
my $dbh = C4::Context->dbh;
# Find the issues record for this book
# based on the value of the RenewalPeriodBase syspref.
unless ($datedue) {
- my $borrower = C4::Members::GetMember( borrowernumber => $borrowernumber ) or return undef;
+ my $borrower = C4::Members::GetMember( borrowernumber => $borrowernumber ) or return;
my $itemtype = (C4::Context->preference('item-level_itypes')) ? $biblio->{'itype'} : $biblio->{'itemtype'};
$datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ?
"Renewal of Rental Item $item->{'title'} $item->{'barcode'}",
'Rent', $charge, $itemnumber );
}
+
+ # Send a renewal slip according to checkout alert preferencei
+ if ( C4::Context->preference('RenewalSendNotice') eq '1') {
+ my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 );
+ my $circulation_alert = 'C4::ItemCirculationAlertPreference';
+ my %conditions = (
+ branchcode => $branch,
+ categorycode => $borrower->{categorycode},
+ item_type => $item->{itype},
+ notification => 'CHECKOUT',
+ );
+ if ($circulation_alert->is_enabled_for(\%conditions)) {
+ SendCirculationAlert({
+ type => 'RENEWAL',
+ item => $item,
+ borrower => $borrower,
+ branch => $branch,
+ });
+ }
+ }
+
# Log the renewal
UpdateStats( $branch, 'renew', $charge, '', $itemnumber, $item->{itype}, $borrowernumber, undef, $item->{'ccode'});
return $datedue;
my %message_name = (
CHECKIN => 'Item_Check_in',
CHECKOUT => 'Item_Checkout',
+ RENEWAL => 'Item_Checkout',
);
my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences({
borrowernumber => $borrower->{borrowernumber},
message_name => $message_name{$type},
});
- my $issues_table = ( $type eq 'CHECKOUT' ) ? 'issues' : 'old_issues';
+ my $issues_table = ( $type eq 'CHECKOUT' || $type eq 'RENEWAL' ) ? 'issues' : 'old_issues';
my $letter = C4::Letters::GetPreparedLetter (
module => 'circulation',
letter_code => $type,
->truncate( to => 'minute' );
if ( $loanlength->{lengthunit} eq 'hours' ) {
$dt->add( hours => $loanlength->{issuelength} );
- return $dt;
} else { # days
$dt->add( days => $loanlength->{issuelength} );
$dt->set_hour(23);
$dt->set_minute(59);
- return $dt;
}
+ # break
+ return $dt;
+
} else {
my $dur;
if ($loanlength->{lengthunit} eq 'hours') {
# if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate
if ( C4::Context->preference('ReturnBeforeExpiry') ) {
my $expiry_dt = dt_from_string( $borrower->{dateexpiry}, 'iso' );
+ $expiry_dt->set( hour => 23, minute => 59);
if ( DateTime->compare( $datedue, $expiry_dt ) == 1 ) {
$datedue = $expiry_dt->clone;
}
);
}
+=head2 CheckIfIssuedToPatron
+
+ CheckIfIssuedToPatron($borrowernumber, $biblionumber)
+
+ Return 1 if any record item is issued to patron, otherwise return 0
+
+=cut
+
+sub CheckIfIssuedToPatron {
+ my ($borrowernumber, $biblionumber) = @_;
+
+ my $items = GetItemsByBiblioitemnumber($biblionumber);
+
+ foreach my $item (@{$items}) {
+ return 1 if ($item->{borrowernumber} && $item->{borrowernumber} eq $borrowernumber);
+ }
+
+ return;
+}
+
1;