use Koha::Account::Lines;
use Koha::Account::Offsets;
use Koha::Config::SysPrefs;
+use Koha::Charges::Fees;
+use Koha::Util::SystemPreferences;
use Carp;
use List::MoreUtils qw( uniq any );
use Scalar::Util qw( looks_like_number );
# if a rule is found and has a loan limit set, count
# how many loans the patron already has that meet that
# rule
- if (defined($maxissueqty_rule) and defined($maxissueqty_rule->rule_value)) {
+ if (defined($maxissueqty_rule) and $maxissueqty_rule->rule_value ne '') {
my @bind_params;
my $count_query = q|
SELECT COUNT(*) AS total, COALESCE(SUM(onsite_checkout), 0) AS onsite_checkouts
|;
my $rule_itemtype = $maxissueqty_rule->itemtype;
- if ($rule_itemtype eq "*") {
+ unless ($rule_itemtype) {
# matching rule has the default item type, so count only
# those existing loans that don't fall under a more
# specific rule
$count_query .= " AND borrowernumber = ? ";
push @bind_params, $borrower->{'borrowernumber'};
my $rule_branch = $maxissueqty_rule->branchcode;
- if ($rule_branch ne "*") {
+ if ($rule_branch) {
if (C4::Context->preference('CircControl') eq 'PickupLibrary') {
$count_query .= " AND issues.branchcode = ? ";
- push @bind_params, $branch;
+ push @bind_params, $rule_branch;
} elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') {
; # if branch is the patron's home branch, then count all loans by patron
} else {
$count_query .= " AND items.homebranch = ? ";
- push @bind_params, $branch;
+ push @bind_params, $rule_branch;
}
}
my ( $checkout_count, $onsite_checkout_count ) = $dbh->selectrow_array( $count_query, {}, @bind_params );
- my $max_checkouts_allowed = $maxissueqty_rule ? $maxissueqty_rule->rule_value : 0;
- my $max_onsite_checkouts_allowed = $maxonsiteissueqty_rule ? $maxonsiteissueqty_rule->rule_value : 0;
+ my $max_checkouts_allowed = $maxissueqty_rule ? $maxissueqty_rule->rule_value : undef;
+ my $max_onsite_checkouts_allowed = $maxonsiteissueqty_rule ? $maxonsiteissueqty_rule->rule_value : undef;
if ( $onsite_checkout and defined $max_onsite_checkouts_allowed ) {
if ( $onsite_checkout_count >= $max_onsite_checkouts_allowed ) {
my $onsite_checkout = $params->{onsite_checkout} || 0;
my $override_high_holds = $params->{override_high_holds} || 0;
- my $item = Koha::Items->find({barcode => $barcode });
+ my $item_object = Koha::Items->find({barcode => $barcode });
+
# MANDATORY CHECKS - unless item exists, nothing else matters
- unless ( $item ) {
+ unless ( $item_object ) {
$issuingimpossible{UNKNOWN_BARCODE} = 1;
}
return ( \%issuingimpossible, \%needsconfirmation ) if %issuingimpossible;
- my $item_unblessed = $item->unblessed; # Transition...
- my $issue = $item->checkout;
- my $biblio = $item->biblio;
+ my $item_unblessed = $item_object->unblessed; # Transition...
+ my $issue = $item_object->checkout;
+ my $biblio = $item_object->biblio;
+
my $biblioitem = $biblio->biblioitem;
- my $effective_itemtype = $item->effective_itemtype;
+ my $effective_itemtype = $item_object->effective_itemtype;
my $dbh = C4::Context->dbh;
my $patron_unblessed = $patron->unblessed;
+ my $circ_library = Koha::Libraries->find( _GetCircControlBranch($item_unblessed, $patron_unblessed) );
#
# DUE DATE is OK ? -- should already have checked.
#
unless ( $duedate ) {
my $issuedate = $now->clone();
- my $branch = _GetCircControlBranch($item_unblessed, $patron_unblessed);
+ my $branch = $circ_library;
$duedate = CalcDateDue( $issuedate, $effective_itemtype, $branch, $patron_unblessed );
# Offline circ calls AddIssue directly, doesn't run through here
# So issuingimpossible should be ok.
}
+
+ my $fees = Koha::Charges::Fees->new(
+ {
+ patron => $patron,
+ library => $circ_library,
+ item => $item_object,
+ to_date => $duedate,
+ }
+ );
+
if ($duedate) {
my $today = $now->clone();
$today->truncate( to => 'minute');
#
# BORROWER STATUS
#
- if ( $patron->category->category_type eq 'X' && ( $item->barcode )) {
+ if ( $patron->category->category_type eq 'X' && ( $item_object->barcode )) {
# stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1 .
&UpdateStats({
branch => C4::Context->userenv->{'branch'},
type => 'localuse',
- itemnumber => $item->itemnumber,
+ itemnumber => $item_object->itemnumber,
itemtype => $effective_itemtype,
borrowernumber => $patron->borrowernumber,
- ccode => $item->ccode}
+ ccode => $item_object->ccode}
);
- ModDateLastSeen( $item->itemnumber ); # FIXME Move to Koha::Item
+ ModDateLastSeen( $item_object->itemnumber ); # FIXME Move to Koha::Item
return( { STATS => 1 }, {});
}
} else {
my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed(
$patron->borrowernumber,
- $item->itemnumber,
+ $item_object->itemnumber,
);
if ( $CanBookBeRenewed == 0 ) { # no more renewals allowed
if ( $renewerror eq 'onsite_checkout' ) {
$issuingimpossible{RETURN_IMPOSSIBLE} = 1;
$issuingimpossible{branch_to_return} = $message;
} else {
+ if ( C4::Context->preference('AutoReturnCheckedOutItems') ) {
+ $alerts{RETURNED_FROM_ANOTHER} = { patron => $patron };
+ } else {
$needsconfirmation{ISSUED_TO_ANOTHER} = 1;
$needsconfirmation{issued_firstname} = $patron->firstname;
$needsconfirmation{issued_surname} = $patron->surname;
$needsconfirmation{issued_cardnumber} = $patron->cardnumber;
$needsconfirmation{issued_borrowernumber} = $patron->borrowernumber;
+ }
}
}
and $issue
and $issue->onsite_checkout
and $issue->borrowernumber == $patron->borrowernumber ? 1 : 0 );
- my $toomany = TooMany( $patron_unblessed, $item->biblionumber, $item_unblessed, { onsite_checkout => $onsite_checkout, switch_onsite_checkout => $switch_onsite_checkout, } );
+ my $toomany = TooMany( $patron_unblessed, $item_object->biblionumber, $item_unblessed, { onsite_checkout => $onsite_checkout, switch_onsite_checkout => $switch_onsite_checkout, } );
# if TooMany max_allowed returns 0 the user doesn't have permission to check out this book
if ( $toomany && not exists $needsconfirmation{RENEW_ISSUE} ) {
if ( $toomany->{max_allowed} == 0 ) {
#
# ITEM CHECKING
#
- if ( $item->notforloan )
+ if ( $item_object->notforloan )
{
if(!C4::Context->preference("AllowNotForLoanOverride")){
$issuingimpossible{NOT_FOR_LOAN} = 1;
- $issuingimpossible{item_notforloan} = $item->notforloan;
+ $issuingimpossible{item_notforloan} = $item_object->notforloan;
}else{
$needsconfirmation{NOT_FOR_LOAN_FORCING} = 1;
- $needsconfirmation{item_notforloan} = $item->notforloan;
+ $needsconfirmation{item_notforloan} = $item_object->notforloan;
}
}
else {
}
}
}
- if ( $item->withdrawn && $item->withdrawn > 0 )
+ if ( $item_object->withdrawn && $item_object->withdrawn > 0 )
{
$issuingimpossible{WTHDRAWN} = 1;
}
- if ( $item->restricted
- && $item->restricted == 1 )
+ if ( $item_object->restricted
+ && $item_object->restricted == 1 )
{
$issuingimpossible{RESTRICTED} = 1;
}
- if ( $item->itemlost && C4::Context->preference("IssueLostItem") ne 'nothing' ) {
- my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $item->itemlost });
+ if ( $item_object->itemlost && C4::Context->preference("IssueLostItem") ne 'nothing' ) {
+ my $av = Koha::AuthorisedValues->search({ category => 'LOST', authorised_value => $item_object->itemlost });
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' );
my $userenv = C4::Context->userenv;
unless ( C4::Context->IsSuperLibrarian() ) {
my $HomeOrHoldingBranch = C4::Context->preference("HomeOrHoldingBranch");
- if ( $item->$HomeOrHoldingBranch ne $userenv->{branch} ){
+ if ( $item_object->$HomeOrHoldingBranch ne $userenv->{branch} ){
$issuingimpossible{ITEMNOTSAMEBRANCH} = 1;
- $issuingimpossible{'itemhomebranch'} = $item->$HomeOrHoldingBranch;
+ $issuingimpossible{'itemhomebranch'} = $item_object->$HomeOrHoldingBranch;
}
$needsconfirmation{BORRNOTSAMEBRANCH} = $patron->branchcode
if ( $patron->branchcode ne $userenv->{branch} );
my $rentalConfirmation = C4::Context->preference("RentalFeesCheckoutConfirmation");
if ( $rentalConfirmation ){
- my ($rentalCharge) = GetIssuingCharges( $item->itemnumber, $patron->borrowernumber );
+ my ($rentalCharge) = GetIssuingCharges( $item_object->itemnumber, $patron->borrowernumber );
+ my $itemtype = Koha::ItemTypes->find( $item_object->itype ); # GetItem sets effective itemtype
+ $rentalCharge += $fees->accumulate_rentalcharge({ from => dt_from_string(), to => $duedate });
if ( $rentalCharge > 0 ){
$needsconfirmation{RENTALCHARGE} = $rentalCharge;
}
unless ( $ignore_reserves ) {
# See if the item is on reserve.
- my ( $restype, $res ) = C4::Reserves::CheckReserves( $item->itemnumber );
+ my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
if ($restype) {
my $resbor = $res->{'borrowernumber'};
if ( $resbor ne $patron->borrowernumber ) {
) {
# Check if borrower has already issued an item from the same biblio
# Only if it's not a subscription
- my $biblionumber = $item->biblionumber;
+ my $biblionumber = $item_object->biblionumber;
require C4::Serials;
my $is_a_subscription = C4::Serials::CountSubscriptionFromBiblionumber($biblionumber);
unless ($is_a_subscription) {
# dynamic means X more than the number of holdable items on the record
# let's get the items
- my @items = $holds->next()->biblio()->items();
+ my @items = $holds->next()->biblio()->items()->as_list;
# Remove any items with status defined to be ignored even if the would not make item unholdable
foreach my $status (@decreaseLoanHighHoldsIgnoreStatuses) {
# Stop here if the patron or barcode doesn't exist
if ( $borrower && $barcode && $barcodecheck ) {
# find which item we issue
- my $item = Koha::Items->find({ barcode => $barcode })
+ my $item_object = Koha::Items->find({ barcode => $barcode })
or return; # if we don't get an Item, abort.
- my $item_unblessed = $item->unblessed;
+ my $item_unblessed = $item_object->unblessed;
my $branch = _GetCircControlBranch( $item_unblessed, $borrower );
# get actual issuing if there is one
- my $actualissue = $item->checkout;
+ my $actualissue = $item_object->checkout;
# check if we just renew the issue.
if ( $actualissue and $actualissue->borrowernumber eq $borrower->{'borrowernumber'}
and not $switch_onsite_checkout ) {
$datedue = AddRenewal(
$borrower->{'borrowernumber'},
- $item->itemnumber,
+ $item_object->itemnumber,
$branch,
$datedue,
$issuedate, # here interpreted as the renewal date
);
}
else {
+ unless ($datedue) {
+ my $itype = $item_object->effective_itemtype;
+ $datedue = CalcDateDue( $issuedate, $itype, $branch, $borrower );
+
+ }
+ $datedue->truncate( to => 'minute' );
+
+ my $patron = Koha::Patrons->find( $borrower );
+ my $library = Koha::Libraries->find( $branch );
+ my $fees = Koha::Charges::Fees->new(
+ {
+ patron => $patron,
+ library => $library,
+ item => $item_object,
+ to_date => $datedue,
+ }
+ );
+
# it's NOT a renewal
if ( $actualissue and not $switch_onsite_checkout ) {
# This book is currently on loan, but not to the person
# who wants to borrow it now. mark it returned before issuing to the new borrower
my ( $allowed, $message ) = CanBookBeReturned( $item_unblessed, C4::Context->userenv->{branch} );
return unless $allowed;
- AddReturn( $item->barcode, C4::Context->userenv->{'branch'} );
+ AddReturn( $item_object->barcode, C4::Context->userenv->{'branch'} );
}
- C4::Reserves::MoveReserve( $item->itemnumber, $borrower->{'borrowernumber'}, $cancelreserve );
+ C4::Reserves::MoveReserve( $item_object->itemnumber, $borrower->{'borrowernumber'}, $cancelreserve );
# Starting process for transfer job (checking transfert and validate it if we have one)
- my ($datesent) = GetTransfers( $item->itemnumber );
+ my ($datesent) = GetTransfers( $item_object->itemnumber );
if ($datesent) {
# updating line of branchtranfert to finish it, and changing the to branch value, implement a comment for visibility of this case (maybe for stats ....)
my $sth = $dbh->prepare(
WHERE itemnumber= ? AND datearrived IS NULL"
);
$sth->execute( C4::Context->userenv->{'branch'},
- $item->itemnumber );
+ $item_object->itemnumber );
}
# If automatic renewal wasn't selected while issuing, set the value according to the issuing rule.
unless ($auto_renew) {
my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
{ categorycode => $borrower->{categorycode},
- itemtype => $item->effective_itemtype,
+ itemtype => $item_object->effective_itemtype,
branchcode => $branch
}
);
# Record in the database the fact that the book was issued.
unless ($datedue) {
- my $itype = $item->effective_itemtype;
+ my $itype = $item_object->effective_itemtype;
$datedue = CalcDateDue( $issuedate, $itype, $branch, $borrower );
}
auto_renew => $auto_renew ? 1 : 0,
};
- $issue = Koha::Checkouts->find( { itemnumber => $item->itemnumber } );
+ $issue = Koha::Checkouts->find( { itemnumber => $item_object->itemnumber } );
if ($issue) {
$issue->set($issue_attributes)->store;
}
else {
$issue = Koha::Checkout->new(
{
- itemnumber => $item->itemnumber,
+ itemnumber => $item_object->itemnumber,
%$issue_attributes,
}
)->store;
}
-
- if ( C4::Context->preference('ReturnToShelvingCart') ) {
- # ReturnToShelvingCart is on, anything issued should be taken off the cart.
- CartToShelf( $item->itemnumber );
+ if ( $item_object->location eq 'CART' && $item_object->permanent_location ne 'CART' ) {
+ ## Item was moved to cart via UpdateItemLocationOnCheckin, anything issued should be taken off the cart.
+ CartToShelf( $item_object->itemnumber );
}
if ( C4::Context->preference('UpdateTotalIssuesOnCirc') ) {
- UpdateTotalIssues( $item->biblionumber, 1 );
+ UpdateTotalIssues( $item_object->biblionumber, 1 );
}
## If item was lost, it has now been found, reverse any list item charges if necessary.
- if ( $item->itemlost ) {
+ if ( $item_object->itemlost ) {
if (
Koha::RefundLostItemFeeRules->should_refund(
{
current_branch => C4::Context->userenv->{branch},
- item_home_branch => $item->homebranch,
- item_holding_branch => $item->holdingbranch,
+ item_home_branch => $item_object->homebranch,
+ item_holding_branch => $item_object->holdingbranch,
}
)
)
{
- _FixAccountForLostAndReturned( $item->itemnumber, undef,
- $item->barcode );
+ _FixAccountForLostAndReturned( $item_object->itemnumber, undef,
+ $item_object->barcode );
}
}
ModItem(
{
- issues => $item->issues + 1,
+ issues => $item_object->issues + 1,
holdingbranch => C4::Context->userenv->{'branch'},
itemlost => 0,
onloan => $datedue->ymd(),
datelastborrowed => DateTime->now( time_zone => C4::Context->tz() )->ymd(),
},
- $item->biblionumber,
- $item->itemnumber,
+ $item_object->biblionumber,
+ $item_object->itemnumber,
{ log_action => 0 }
);
- ModDateLastSeen( $item->itemnumber );
+ ModDateLastSeen( $item_object->itemnumber );
- # If it costs to borrow this book, charge it to the patron's account.
- my ( $charge, $itemtype ) = GetIssuingCharges( $item->itemnumber, $borrower->{'borrowernumber'} );
+ # If it costs to borrow this book, charge it to the patron's account.
+ my ( $charge, $itemtype ) = GetIssuingCharges( $item_object->itemnumber, $borrower->{'borrowernumber'} );
if ( $charge > 0 ) {
- AddIssuingCharge( $issue, $charge );
+ my $description = "Rental";
+ AddIssuingCharge( $issue, $charge, $description );
+ }
+
+ my $itemtype_object = Koha::ItemTypes->find( $item_object->effective_itemtype );
+ if ( $itemtype_object ) {
+ my $accumulate_charge = $fees->accumulate_rentalcharge();
+ if ( $accumulate_charge > 0 ) {
+ AddIssuingCharge( $issue, $accumulate_charge, 'Daily rental' ) if $accumulate_charge > 0;
+ $charge += $accumulate_charge;
+ $item_unblessed->{charge} = $charge;
+ }
}
# Record the fact that this book was issued.
type => ( $onsite_checkout ? 'onsite_checkout' : 'issue' ),
amount => $charge,
other => ( $sipmode ? "SIP-$sipmode" : '' ),
- itemnumber => $item->itemnumber,
- itemtype => $item->effective_itemtype,
- location => $item->location,
+ itemnumber => $item_object->itemnumber,
+ itemtype => $item_object->effective_itemtype,
+ location => $item_object->location,
borrowernumber => $borrower->{'borrowernumber'},
- ccode => $item->ccode,
+ ccode => $item_object->ccode,
}
);
my %conditions = (
branchcode => $branch,
categorycode => $borrower->{categorycode},
- item_type => $item->effective_itemtype,
+ item_type => $item_object->effective_itemtype,
notification => 'CHECKOUT',
);
if ( $circulation_alert->is_enabled_for( \%conditions ) ) {
SendCirculationAlert(
{
type => 'CHECKOUT',
- item => $item->unblessed,
+ item => $item_object->unblessed,
borrower => $borrower,
branch => $branch,
}
logaction(
"CIRCULATION", "ISSUE",
$borrower->{'borrowernumber'},
- $item->itemnumber,
+ $item_object->itemnumber,
) if C4::Context->preference("IssueLog");
}
}
sub GetBranchBorrowerCircRule {
my ( $branchcode, $categorycode ) = @_;
- # Set search prededences
- my @params = (
- {
- branchcode => $branchcode,
- categorycode => $categorycode,
- itemtype => undef,
- },
- {
- branchcode => $branchcode,
- categorycode => undef,
- itemtype => undef,
- },
- {
- branchcode => undef,
- categorycode => $categorycode,
- itemtype => undef,
- },
- {
- branchcode => undef,
- categorycode => undef,
- itemtype => undef,
- },
- );
-
# Initialize default values
my $rules = {
patron_maxissueqty => undef,
# Search for rules!
foreach my $rule_name (qw( patron_maxissueqty patron_maxonsiteissueqty )) {
- foreach my $params (@params) {
- my $rule = Koha::CirculationRules->search(
- {
- rule_name => $rule_name,
- %$params,
- }
- )->next();
-
- if ( $rule ) {
- $rules->{$rule_name} = $rule->rule_value;
- last;
+ my $rule = Koha::CirculationRules->get_effective_rule(
+ {
+ categorycode => $categorycode,
+ itemtype => undef,
+ branchcode => $branchcode,
+ rule_name => $rule_name,
}
- }
+ );
+
+ $rules->{$rule_name} = $rule->rule_value if defined $rule;
}
return $rules;
sub GetBranchItemRule {
my ( $branchcode, $itemtype ) = @_;
- my $dbh = C4::Context->dbh();
- my $result = {};
-
- my @attempts = (
- ['SELECT holdallowed, returnbranch, hold_fulfillment_policy
- FROM branch_item_rules
- WHERE branchcode = ?
- AND itemtype = ?', $branchcode, $itemtype],
- ['SELECT holdallowed, returnbranch, hold_fulfillment_policy
- FROM default_branch_circ_rules
- WHERE branchcode = ?', $branchcode],
- ['SELECT holdallowed, returnbranch, hold_fulfillment_policy
- FROM default_branch_item_rules
- WHERE itemtype = ?', $itemtype],
- ['SELECT holdallowed, returnbranch, hold_fulfillment_policy
- FROM default_circ_rules'],
+
+ # Search for rules!
+ my $holdallowed_rule = Koha::CirculationRules->get_effective_rule(
+ {
+ branchcode => $branchcode,
+ itemtype => $itemtype,
+ rule_name => 'holdallowed',
+ }
+ );
+ my $hold_fulfillment_policy_rule = Koha::CirculationRules->get_effective_rule(
+ {
+ branchcode => $branchcode,
+ itemtype => $itemtype,
+ rule_name => 'hold_fulfillment_policy',
+ }
+ );
+ my $returnbranch_rule = Koha::CirculationRules->get_effective_rule(
+ {
+ branchcode => $branchcode,
+ itemtype => $itemtype,
+ rule_name => 'returnbranch',
+ }
);
- foreach my $attempt (@attempts) {
- my ($query, @bind_params) = @{$attempt};
- my $search_result = $dbh->selectrow_hashref ( $query , {}, @bind_params )
- or next;
-
- # Since branch/category and branch/itemtype use the same per-branch
- # defaults tables, we have to check that the key we want is set, not
- # just that a row was returned
- $result->{'holdallowed'} = $search_result->{'holdallowed'} unless ( defined $result->{'holdallowed'} );
- $result->{'hold_fulfillment_policy'} = $search_result->{'hold_fulfillment_policy'} unless ( defined $result->{'hold_fulfillment_policy'} );
- $result->{'returnbranch'} = $search_result->{'returnbranch'} unless ( defined $result->{'returnbranch'} );
- }
-
# built-in default circulation rule
- $result->{'holdallowed'} = 2 unless ( defined $result->{'holdallowed'} );
- $result->{'hold_fulfillment_policy'} = 'any' unless ( defined $result->{'hold_fulfillment_policy'} );
- $result->{'returnbranch'} = 'homebranch' unless ( defined $result->{'returnbranch'} );
+ my $rules;
+ $rules->{holdallowed} = defined $holdallowed_rule
+ ? $holdallowed_rule->rule_value
+ : 2;
+ $rules->{hold_fulfillment_policy} = defined $hold_fulfillment_policy_rule
+ ? $hold_fulfillment_policy_rule->rule_value
+ : 'any';
+ $rules->{returnbranch} = defined $returnbranch_rule
+ ? $returnbranch_rule->rule_value
+ : 'homebranch';
- return $result;
+ return $rules;
}
=head2 AddReturn
($doreturn, $messages, $iteminformation, $borrower) =
- &AddReturn( $barcode, $branch [,$exemptfine] [,$dropbox] [,$returndate] );
+ &AddReturn( $barcode, $branch [,$exemptfine] [,$returndate] );
Returns a book.
=item C<$exemptfine> indicates that overdue charges for the item will be
removed. Optional.
-=item C<$dropbox> indicates that the check-in date is assumed to be
-yesterday, or the last non-holiday as defined in C4::Calendar . If
-overdue charges are applied and C<$dropbox> is true, the last charge
-will be removed. This assumes that the fines accrual script has run
-for _today_. Optional.
-
=item C<$return_date> allows the default return date to be overridden
by the given return date. Optional.
=cut
sub AddReturn {
- my ( $barcode, $branch, $exemptfine, $dropbox, $return_date, $dropboxdate ) = @_;
+ my ( $barcode, $branch, $exemptfine, $return_date ) = @_;
if ($branch and not Koha::Libraries->find($branch)) {
warn "AddReturn error: branch '$branch' not found. Reverting to " . C4::Context->userenv->{'branch'};
undef $branch;
}
$branch = C4::Context->userenv->{'branch'} unless $branch; # we trust userenv to be a safe fallback/default
+ $return_date //= dt_from_string();
my $messages;
my $patron;
my $doreturn = 1;
}
my $item_unblessed = $item->unblessed;
- if ( $item->location eq 'PROC' ) {
- if ( C4::Context->preference("InProcessingToShelvingCart") ) {
- $item_unblessed->{location} = 'CART';
- }
- else {
- $item_unblessed->{location} = $item->permanent_location;
- }
-
- ModItem( $item_unblessed, $item->biblionumber, $item->itemnumber, { log_action => 0 } );
- }
-
# full item data, but no borrowernumber or checkout info (no issue)
my $hbr = GetBranchItemRule($item->homebranch, $itemtype)->{'returnbranch'} || "homebranch";
# get the proper branch to which to return the item
my $borrowernumber = $patron ? $patron->borrowernumber : undef; # we don't know if we had a borrower or not
my $patron_unblessed = $patron ? $patron->unblessed : {};
+ my $update_loc_rules = get_yaml_pref_hash('UpdateItemLocationOnCheckin');
+ map { $update_loc_rules->{$_} = $update_loc_rules->{$_}[0] } keys %$update_loc_rules; #We can only move to one location so we flatten the arrays
+ if ($update_loc_rules) {
+ if (defined $update_loc_rules->{_ALL_}) {
+ if ($update_loc_rules->{_ALL_} eq '_PERM_') { $update_loc_rules->{_ALL_} = $item->permanent_location; }
+ if ($update_loc_rules->{_ALL_} eq '_BLANK_') { $update_loc_rules->{_ALL_} = ''; }
+ if ( $item->location ne $update_loc_rules->{_ALL_}) {
+ $messages->{'ItemLocationUpdated'} = { from => $item->location, to => $update_loc_rules->{_ALL_} };
+ ModItem( { location => $update_loc_rules->{_ALL_} }, undef, $itemnumber );
+ }
+ }
+ else {
+ foreach my $key ( keys %$update_loc_rules ) {
+ if ( $update_loc_rules->{$key} eq '_PERM_' ) { $update_loc_rules->{$key} = $item->permanent_location; }
+ if ( $update_loc_rules->{$key} eq '_BLANK_') { $update_loc_rules->{$key} = '' ;}
+ if ( ($item->location eq $key && $item->location ne $update_loc_rules->{$key}) || ($key eq '_BLANK_' && $item->location eq '' && $update_loc_rules->{$key} ne '') ) {
+ $messages->{'ItemLocationUpdated'} = { from => $item->location, to => $update_loc_rules->{$key} };
+ ModItem( { location => $update_loc_rules->{$key} }, undef, $itemnumber );
+ last;
+ }
+ }
+ }
+ }
+
my $yaml = C4::Context->preference('UpdateNotForLoanStatusOnCheckin');
if ($yaml) {
$yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
}
# case of a return of document (deal with issues and holdingbranch)
- my $today = DateTime->now( time_zone => C4::Context->tz() );
-
if ($doreturn) {
my $is_overdue;
die "The item is not issed and cannot be returned" unless $issue; # Just in case...
$patron or warn "AddReturn without current borrower";
- if ($dropbox) {
- $is_overdue = $issue->is_overdue( $dropboxdate );
- } else {
- $is_overdue = $issue->is_overdue;
- }
+ $is_overdue = $issue->is_overdue( $return_date );
if ($patron) {
eval {
- if ( $dropbox ) {
- MarkIssueReturned( $borrowernumber, $item->itemnumber,
- $dropboxdate, $patron->privacy );
- }
- else {
- MarkIssueReturned( $borrowernumber, $item->itemnumber,
- $return_date, $patron->privacy );
- }
+ MarkIssueReturned( $borrowernumber, $item->itemnumber, $return_date, $patron->privacy );
};
unless ( $@ ) {
- if ( ( C4::Context->preference('CalculateFinesOnReturn') && $is_overdue ) || $return_date ) {
+ if ( C4::Context->preference('CalculateFinesOnReturn') && $is_overdue && !$item->itemlost ) {
_CalculateAndUpdateFine( { issue => $issue, item => $item_unblessed, borrower => $patron_unblessed, return_date => $return_date } );
}
} else {
);
$sth->execute( $item->itemnumber );
# if we have a reservation with valid transfer, we can set it's status to 'W'
- ShelfToCart( $item->itemnumber ) if ( C4::Context->preference("ReturnToShelvingCart") );
C4::Reserves::ModReserveStatus($item->itemnumber, 'W');
} else {
$messages->{'WrongTransfer'} = $tobranch;
$messages->{'WrongTransferItem'} = $item->itemnumber;
}
$validTransfert = 1;
- } else {
- ShelfToCart( $item->itemnumber ) if ( C4::Context->preference("ReturnToShelvingCart") );
}
# fix up the accounts.....
# fix up the overdues in accounts...
if ($borrowernumber) {
- my $fix = _FixOverduesOnReturn($borrowernumber, $item->itemnumber, $exemptfine, $dropbox);
+ my $fix = _FixOverduesOnReturn( $borrowernumber, $item->itemnumber, $exemptfine );
defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->itemnumber...) failed!"; # zero is OK, check defined
if ( $issue and $issue->is_overdue ) {
# fix fine days
- $today = dt_from_string($return_date) if $return_date;
- $today = $dropboxdate if $dropbox;
- my ($debardate,$reminder) = _debar_user_on_return( $patron_unblessed, $item_unblessed, dt_from_string($issue->date_due), $today );
+ 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 {
} else {
my $borrower_debar_dt = dt_from_string( $patron->debarred );
$borrower_debar_dt->truncate(to => 'day');
- my $today_dt = $today->clone()->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;
}
=head2 _debar_user_on_return
- _debar_user_on_return($borrower, $item, $datedue, today);
+ _debar_user_on_return($borrower, $item, $datedue, $returndate);
C<$borrower> borrower hashref
C<$datedue> date due DateTime object
-C<$return_date> DateTime object representing the return time
+C<$returndate> DateTime object representing the return time
Internal function, called only by AddReturn that calculates and updates
the user fine days, and debars them if necessary.
my ( $borrower, $item, $dt_due, $return_date ) = @_;
my $branchcode = _GetCircControlBranch( $item, $borrower );
+ $return_date //= dt_from_string();
my $circcontrol = C4::Context->preference('CircControl');
my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule(
=head2 _FixOverduesOnReturn
- &_FixOverduesOnReturn($brn,$itm, $exemptfine, $dropboxmode);
+ &_FixOverduesOnReturn($borrowernumber, $itemnumber, $exemptfine);
-C<$brn> borrowernumber
+C<$borrowernumber> borrowernumber
-C<$itm> itemnumber
+C<$itemnumber> itemnumber
C<$exemptfine> BOOL -- remove overdue charge associated with this issue.
-C<$dropboxmode> BOOL -- remove lastincrement on overdue charge associated with this issue.
Internal function
=cut
sub _FixOverduesOnReturn {
- my ($borrowernumber, $item, $exemptfine, $dropbox ) = @_;
+ my ( $borrowernumber, $item, $exemptfine ) = @_;
unless( $borrowernumber ) {
warn "_FixOverduesOnReturn() not supplied valid borrowernumber";
return;
return;
}
- # check for overdue fine
- my $accountline = Koha::Account::Lines->search(
- {
- borrowernumber => $borrowernumber,
- itemnumber => $item,
- -or => [
- accounttype => 'FU',
- accounttype => 'O',
- ],
- }
- )->next();
- return 0 unless $accountline; # no warning, there's just nothing to fix
-
- if ($exemptfine) {
- my $amountoutstanding = $accountline->amountoutstanding;
+ my $schema = Koha::Database->schema;
- $accountline->accounttype('FFOR');
- $accountline->amountoutstanding(0);
+ my $result = $schema->txn_do(
+ sub {
+ # check for overdue fine
+ my $accountlines = Koha::Account::Lines->search(
+ {
+ borrowernumber => $borrowernumber,
+ itemnumber => $item,
+ accounttype => 'OVERDUE',
+ status => 'UNRETURNED'
+ }
+ );
+ return 0 unless $accountlines->count; # no warning, there's just nothing to fix
- Koha::Account::Offset->new(
- {
- debit_id => $accountline->id,
- type => 'Forgiven',
- amount => $amountoutstanding * -1,
- }
- )->store();
+ my $accountline = $accountlines->next;
+ if ($exemptfine) {
+ my $amountoutstanding = $accountline->amountoutstanding;
- if (C4::Context->preference("FinesLog")) {
- &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item");
- }
- } elsif ($dropbox && $accountline->lastincrement) {
- my $outstanding = $accountline->amountoutstanding - $accountline->lastincrement;
- my $amt = $accountline->amount - $accountline->lastincrement;
+ my $account = Koha::Account->new({patron_id => $borrowernumber});
+ my $credit = $account->add_credit(
+ {
+ amount => $amountoutstanding,
+ user_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
+ library_id => C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef,
+ interface => C4::Context->interface,
+ type => 'forgiven',
+ item_id => $item
+ }
+ );
- Koha::Account::Offset->new(
- {
- debit_id => $accountline->id,
- type => 'Dropbox',
- amount => $accountline->lastincrement * -1,
- }
- )->store();
+ $credit->apply({ debits => $accountlines->reset, offset_type => 'Forgiven' });
- if ( C4::Context->preference("FinesLog") ) {
- &logaction( "FINES", 'MODIFY', $borrowernumber,
- "Dropbox adjustment $amt, item $item" );
- }
+ $accountline->status('FORGIVEN');
- $accountline->accounttype('F');
+ if (C4::Context->preference("FinesLog")) {
+ &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item");
+ }
+ } else {
+ $accountline->status('RETURNED');
+ }
- if ( $outstanding >= 0 && $amt >= 0 ) {
- $accountline->amount($amt);
- $accountline->amountoutstanding($outstanding);
+ return $accountline->store();
}
+ );
- } else {
- $accountline->accounttype('F');
- }
-
- return $accountline->store();
+ return $result;
}
=head2 _FixAccountForLostAndReturned
my $accountlines = Koha::Account::Lines->search(
{
itemnumber => $itemnumber,
- accounttype => { -in => [ 'L', 'Rep', 'W' ] },
+ accounttype => 'L',
},
{
- order_by => { -desc => [ 'date', 'accountno' ] }
+ order_by => { -desc => [ 'date', 'accountlines_id' ] }
}
);
return unless $accountlines->count > 0;
my $accountline = $accountlines->next;
my $total_to_refund = 0;
- my $account = Koha::Patrons->find( $accountline->borrowernumber )->account;
+
+ return unless $accountline->borrowernumber;
+ my $patron = Koha::Patrons->find( $accountline->borrowernumber );
+ return unless $patron; # Patron has been deleted, nobody to credit the return to
+
+ my $account = $patron->account;
# Use cases
if ( $accountline->amount > $accountline->amountoutstanding ) {
{ amount => $credit_total,
description => 'Item Returned ' . $item_id,
type => 'lost_item_return',
+ interface => C4::Context->interface,
library_id => $branchcode
}
);
# can be filled with available items. We can get the union of the sets simply
# by pushing all the elements onto an array and removing the duplicates.
my @reservable;
- my %borrowers;
- ITEM: foreach my $i (@itemnumbers) {
- my $item = Koha::Items->find($i)->unblessed;
- next if IsItemOnHoldAndFound($i);
- for my $b (@borrowernumbers) {
- my $borr = $borrowers{$b} //= Koha::Patrons->find( $b )->unblessed;
- next unless IsAvailableForItemLevelRequest($item, $borr);
- next unless CanItemBeReserved($b,$i);
-
- push @reservable, $i;
+ my %patrons;
+ ITEM: foreach my $itemnumber (@itemnumbers) {
+ my $item = Koha::Items->find( $itemnumber );
+ next if IsItemOnHoldAndFound( $itemnumber );
+ for my $borrowernumber (@borrowernumbers) {
+ my $patron = $patrons{$borrowernumber} //= Koha::Patrons->find( $borrowernumber );
+ next unless IsAvailableForItemLevelRequest($item, $patron);
+ next unless CanItemBeReserved($borrowernumber,$itemnumber);
+
+ push @reservable, $itemnumber;
if (@reservable >= @borrowernumbers) {
$resfound = 0;
last ITEM;
my $datedue = shift;
my $lastreneweddate = shift || DateTime->now(time_zone => C4::Context->tz);
- my $item = Koha::Items->find($itemnumber) or return;
- my $biblio = $item->biblio;
- my $issue = $item->checkout;
- my $item_unblessed = $item->unblessed;
+ my $item_object = Koha::Items->find($itemnumber) or return;
+ my $biblio = $item_object->biblio;
+ my $issue = $item_object->checkout;
+ my $item_unblessed = $item_object->unblessed;
my $dbh = C4::Context->dbh;
my $patron = Koha::Patrons->find( $borrowernumber ) or return; # FIXME Should do more than just return
my $patron_unblessed = $patron->unblessed;
+ my $circ_library = Koha::Libraries->find( _GetCircControlBranch($item_unblessed, $patron_unblessed) );
+
if ( C4::Context->preference('CalculateFinesOnReturn') && $issue->is_overdue ) {
_CalculateAndUpdateFine( { issue => $issue, item => $item_unblessed, borrower => $patron_unblessed } );
}
# If the due date wasn't specified, calculate it by adding the
# book's loan length to today's date or the current due date
# based on the value of the RenewalPeriodBase syspref.
+ my $itemtype = $item_object->effective_itemtype;
unless ($datedue) {
- my $itemtype = $item->effective_itemtype;
$datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ?
dt_from_string( $issue->date_due, 'sql' ) :
DateTime->now( time_zone => C4::Context->tz());
- $datedue = CalcDateDue($datedue, $itemtype, _GetCircControlBranch($item_unblessed, $patron_unblessed), $patron_unblessed, 'is a renewal');
+ $datedue = CalcDateDue($datedue, $itemtype, $circ_library->branchcode, $patron_unblessed, 'is a renewal');
}
+ my $fees = Koha::Charges::Fees->new(
+ {
+ patron => $patron,
+ library => $circ_library,
+ item => $item_object,
+ from_date => dt_from_string( $issue->date_due, 'sql' ),
+ to_date => dt_from_string($datedue),
+ }
+ );
+
# Update the issues record to have the new due date, and a new count
# of how many times it has been renewed.
my $renews = $issue->renewals + 1;
$sth->execute( $datedue->strftime('%Y-%m-%d %H:%M'), $renews, $lastreneweddate, $borrowernumber, $itemnumber );
# Update the renewal count on the item, and tell zebra to reindex
- $renews = $item->renewals + 1;
- ModItem( { renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M')}, $item->biblionumber, $itemnumber, { log_action => 0 } );
+ $renews = $item_object->renewals + 1;
+ ModItem( { renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M')}, $item_object->biblionumber, $itemnumber, { log_action => 0 } );
- # Charge a new rental fee, if applicable?
+ # Charge a new rental fee, if applicable
my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
if ( $charge > 0 ) {
- my $accountno = C4::Accounts::getnextacctno( $borrowernumber );
- my $manager_id = 0;
- $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
- my $branchcode = C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
- Koha::Account::Line->new(
- {
- date => dt_from_string(),
- borrowernumber => $borrowernumber,
- accountno => $accountno,
- amount => $charge,
- manager_id => $manager_id,
- accounttype => 'Rent',
- amountoutstanding => $charge,
- itemnumber => $itemnumber,
- branchcode => $branchcode,
- description => 'Renewal of Rental Item '
- . $biblio->title
- . " " . $item->barcode,
- }
- )->store();
+ my $description = "Renewal of Rental Item " . $biblio->title . " " .$item_object->barcode;
+ AddIssuingCharge($issue, $charge, $description);
+ }
+
+ # Charge a new accumulate rental fee, if applicable
+ my $itemtype_object = Koha::ItemTypes->find( $itemtype );
+ if ( $itemtype_object ) {
+ my $accumulate_charge = $fees->accumulate_rentalcharge();
+ if ( $accumulate_charge > 0 ) {
+ my $type_desc = "Renewal of Daily Rental Item " . $biblio->title . " $item_unblessed->{'barcode'}";
+ AddIssuingCharge( $issue, $accumulate_charge, $type_desc )
+ }
+ $charge += $accumulate_charge;
}
# Send a renewal slip according to checkout alert preferencei
my %conditions = (
branchcode => $branch,
categorycode => $patron->categorycode,
- item_type => $item->effective_itemtype,
+ item_type => $itemtype,
notification => 'CHECKOUT',
);
if ( $circulation_alert->is_enabled_for( \%conditions ) ) {
type => 'renew',
amount => $charge,
itemnumber => $itemnumber,
- itemtype => $item->effective_itemtype,
- location => $item->location,
+ itemtype => $itemtype,
+ location => $item_object->location,
borrowernumber => $borrowernumber,
- ccode => $item->ccode,
+ ccode => $item_object->ccode,
}
);
=head2 AddIssuingCharge
- &AddIssuingCharge( $checkout, $charge )
+ &AddIssuingCharge( $checkout, $charge, [$description] )
=cut
sub AddIssuingCharge {
- my ( $checkout, $charge ) = @_;
+ my ( $checkout, $charge, $description ) = @_;
# FIXME What if checkout does not exist?
my $accountline = $account->add_debit(
{
amount => $charge,
- description => 'Rental',
+ description => $description,
note => undef,
- user_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0,
+ user_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
library_id => C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef,
+ interface => C4::Context->interface,
type => 'rent',
item_id => $checkout->itemnumber,
issue_id => $checkout->issue_id,
defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!"; # zero is OK, check defined
if (C4::Context->preference('WhenLostChargeReplacementFee')){
- C4::Accounts::chargelostitem($borrowernumber, $itemnumber, $issues->{'replacementprice'}, "Lost Item $issues->{'title'} $issues->{'barcode'} $issues->{'itemcallnumber'}");
+ C4::Accounts::chargelostitem($borrowernumber, $itemnumber, $issues->{'replacementprice'}, "$issues->{'title'} $issues->{'barcode'} $issues->{'itemcallnumber'}");
#FIXME : Should probably have a way to distinguish this from an item that really was returned.
#warn " $issues->{'borrowernumber'} / $itemnumber ";
}
my $patron = Koha::Patrons->find({ cardnumber => $operation->{cardnumber} });
- $patron->account->pay({ amount => $operation->{amount}, library_id => $operation->{branchcode} });
+ $patron->account->pay(
+ {
+ amount => $operation->{amount},
+ library_id => $operation->{branchcode},
+ interface => 'koc'
+ }
+ );
return "Success.";
}
: ( $control eq 'PatronLibrary' ) ? $borrower->{branchcode}
: $issue->branchcode;
- my $date_returned = $return_date ? dt_from_string($return_date) : dt_from_string();
+ my $date_returned = $return_date ? $return_date : dt_from_string();
my ( $amount, $unitcounttotal, $unitcount ) =
C4::Overdues::CalcFine( $item, $borrower->{categorycode}, $control_branchcode, $datedue, $date_returned );