use YAML::XS;
use Encode;
-use Koha::DateUtils qw( dt_from_string output_pref );
use C4::Context;
use C4::Stats qw( UpdateStats );
use C4::Reserves qw( CheckReserves CanItemBeReserved MoveReserve ModReserve ModReserveMinusPriority RevertWaitingStatus IsItemOnHoldAndFound IsAvailableForItemLevelRequest ItemsAnyAvailableAndNotRestricted );
use Koha::AuthorisedValues;
use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue;
use Koha::Biblioitems;
-use Koha::DateUtils qw( dt_from_string output_pref );
+use Koha::DateUtils qw( dt_from_string );
use Koha::Calendar;
use Koha::Checkouts;
use Koha::Illrequests;
GetBranchBorrowerCircRule
GetBranchItemRule
GetBiblioIssues
- GetOpenIssue
GetUpcomingDueIssues
CheckIfIssuedToPatron
IsItemIssued
transferbook
TooMany
- GetTransfers
GetTransfersFromTo
updateWrongTransfer
CalcDateDue
DeleteOfflineOperation
ProcessOfflineOperation
ProcessOfflinePayment
+ ProcessOfflineIssue
);
push @EXPORT_OK, '_GetCircControlBranch'; # This is wrong!
}
my $now = dt_from_string();
$duedate ||= CalcDateDue( $now, $effective_itemtype, $circ_library->branchcode, $patron_unblessed );
if (DateTime->compare($duedate,$now) == -1 ) { # duedate cannot be before now
- $needsconfirmation{INVALID_DATE} = output_pref($duedate);
+ $needsconfirmation{INVALID_DATE} = $duedate;
}
my $fees = Koha::Charges::Fees->new(
my $check = checkHighHolds( $item_object, $patron );
if ( $check->{exceeded} ) {
+ my $highholds = {
+ num_holds => $check->{outstanding},
+ duration => $check->{duration},
+ returndate => $check->{due_date},
+ };
if ($override_high_holds) {
- $alerts{HIGHHOLDS} = {
- num_holds => $check->{outstanding},
- duration => $check->{duration},
- returndate => output_pref( { dt => dt_from_string($check->{due_date}), dateformat => 'iso', timeformat => '24hr' }),
- };
+ $alerts{HIGHHOLDS} = $highholds;
}
else {
- $needsconfirmation{HIGHHOLDS} = {
- num_holds => $check->{outstanding},
- duration => $check->{duration},
- returndate => output_pref( { dt => dt_from_string($check->{due_date}), dateformat => 'iso', timeformat => '24hr' }),
- };
+ $needsconfirmation{HIGHHOLDS} = $highholds;
}
}
}
=item C<$cancelreserve> is 1 to override and cancel any pending reserves for the item (optional).
-=item C<$issuedate> is the date to issue the item in iso (YYYY-MM-DD) format (optional).
-Defaults to today. Unlike C<$datedue>, NOT a DateTime object, unfortunately.
+=item C<$issuedate> is a DateTime object for the date to issue the item (optional).
+Defaults to today.
AddIssue does the following things :
my $issue_attributes = {
borrowernumber => $borrower->{'borrowernumber'},
- issuedate => $issuedate->strftime('%Y-%m-%d %H:%M:%S'),
- date_due => $datedue->strftime('%Y-%m-%d %H:%M:%S'),
+ issuedate => $issuedate,
+ date_due => $datedue,
branchcode => C4::Context->userenv->{'branch'},
onsite_checkout => $onsite_checkout,
auto_renew => $auto_renew ? 1 : 0,
}
}
+ # Check for bundle status
+ if ( $item->in_bundle ) {
+ my $host = $item->bundle_host;
+ $messages->{InBundle} = $host;
+ }
+
my $indexer = Koha::SearchEngine::Indexer->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
$indexer->index_records( $item->biblionumber, "specialUpdate", "biblioserver" );
return $branch;
}
-=head2 GetOpenIssue
-
- $issue = GetOpenIssue( $itemnumber );
-
-Returns the row from the issues table if the item is currently issued, undef if the item is not currently issued
-
-C<$itemnumber> is the item's itemnumber
-
-Returns a hashref
-
-=cut
-
-sub GetOpenIssue {
- my ( $itemnumber ) = @_;
- return unless $itemnumber;
- my $dbh = C4::Context->dbh;
- my $sth = $dbh->prepare( "SELECT * FROM issues WHERE itemnumber = ? AND returndate IS NULL" );
- $sth->execute( $itemnumber );
- return $sth->fetchrow_hashref();
-
-}
-
=head2 GetUpcomingDueIssues
my $upcoming_dues = GetUpcomingDueIssues( { days_in_advance => 4 } );
return ( 0, "too_unseen" )
if C4::Context->preference('UnseenRenewals') &&
- $issuing_rule->{unseen_renewals_allowed} &&
+ looks_like_number($issuing_rule->{unseen_renewals_allowed}) &&
$issuing_rule->{unseen_renewals_allowed} <= $issue->unseen_renewals;
my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
}
}
- # Note: possible_reserves will contain all title level holds on this bib and item level
- # holds on the checked out item
- my ( $resfound, $resrec, $possible_reserves ) = C4::Reserves::CheckReserves($itemnumber);
-
- # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
- if ( $resfound && $resrec->{non_priority} ) {
- $resfound = Koha::Holds->search(
- { biblionumber => $resrec->{biblionumber}, non_priority => 0 } )
- ->count > 0;
- }
-
-
-
- # This item can fill one or more unfilled reserve, can those unfilled reserves
- # all be filled by other available items?
- if ( $resfound
- && C4::Context->preference('AllowRenewalIfOtherItemsAvailable') )
- {
- my $item_holds = Koha::Holds->search( { itemnumber => $itemnumber, found => undef } )->count();
- if ($item_holds) {
- # There is an item level hold on this item, no other item can fill the hold
- $resfound = 1;
- }
- else {
+ my $fillable_holds = Koha::Holds->search(
+ {
+ biblionumber => $item->biblionumber,
+ non_priority => 0,
+ found => undef,
+ reservedate => { '<=' => \'NOW()' },
+ suspend => 0,
+ },
+ { prefetch => 'patron' }
+ );
+ if ( $fillable_holds->count ) {
+ if ( C4::Context->preference('AllowRenewalIfOtherItemsAvailable') ) {
+ my @possible_holds = $fillable_holds->as_list;
# Get all other items that could possibly fill reserves
# FIXME We could join reserves (or more tables) here to eliminate some checks later
- my $items = Koha::Items->search({
- biblionumber => $resrec->{biblionumber},
+ my @other_items = Koha::Items->search({
+ biblionumber => $item->biblionumber,
onloan => undef,
notforloan => 0,
- -not => { itemnumber => $itemnumber }
- });
- my $item_count = $items->count();
-
- # Get all other reserves that could have been filled by this item
- my @borrowernumbers = map { $_->{borrowernumber} } @$possible_reserves;
- # Note: fetching the patrons in this manner means that a patron with 2 holds will
- # not block renewal if one reserve can be satisfied i.e. each patron is checked once
- my $patrons = Koha::Patrons->search({
- borrowernumber => { -in => \@borrowernumbers }
- });
- my $patron_count = $patrons->count();
+ -not => { itemnumber => $itemnumber } })->as_list;
- return ( 0, "on_reserve" ) if ($patron_count > $item_count);
- # We cannot possibly fill all reserves if we don't have enough items
+ return ( 0, "on_reserve" ) if @possible_holds && (scalar @other_items < scalar @possible_holds);
- # If we can fill each hold that has been found with the available items on the record
- # then the patron can renew. If we cannot, they cannot renew.
- # FIXME This code does not check whether the item we are renewing can fill
- # any of the existing reserves.
- my $reservable = 0;
my %matched_items;
- my $seen = 0;
- PATRON: while ( my $patron = $patrons->next ) {
- # If there is a reserve that cannot be filled we are done
- return ( 0, "on_reserve" ) if ( $seen > $reservable );
- my $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $item->biblionumber, patron => $patron });
- while ( my $other_item = $items->next ) {
- next if defined $matched_items{$other_item->itemnumber};
- next if IsItemOnHoldAndFound( $other_item->itemnumber );
- next unless IsAvailableForItemLevelRequest($other_item, $patron, undef, $items_any_available);
- next unless CanItemBeReserved($patron,$other_item,undef,{ignore_hold_counts=>1})->{status} eq 'OK';
- # NOTE: At checkin we call 'CheckReserves' which checks hold 'policy'
- # CanItemBeReserved checks 'rules' and 'policies' which means
- # items will fill holds at checkin that are rejected here
- $reservable++;
- if ($reservable >= $patron_count) {
- $resfound = 0;
- last PATRON;
- }
- $matched_items{$other_item->itemnumber} = 1;
- last;
+ foreach my $possible_hold (@possible_holds) {
+ my $fillable = 0;
+ my $patron_with_reserve = Koha::Patrons->find($possible_hold->borrowernumber);
+ my $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $item->biblionumber, patron => $patron_with_reserve });
+
+ # FIXME: We are not checking whether the item we are renewing can fill the hold
+
+ foreach my $other_item (@other_items) {
+ next if defined $matched_items{$other_item->itemnumber};
+ next if IsItemOnHoldAndFound( $other_item->itemnumber );
+ next unless IsAvailableForItemLevelRequest($other_item, $patron_with_reserve, undef, $items_any_available);
+ next unless CanItemBeReserved($patron_with_reserve,$other_item,undef,{ignore_hold_counts=>1})->{status} eq 'OK';
+ # NOTE: At checkin we call 'CheckReserves' which checks hold 'policy'
+ # CanItemBeReserved checks 'rules' and 'policies' which means
+ # items will fill holds at checkin that are rejected here
+ $fillable = 1;
+ $matched_items{$other_item->itemnumber} = 1;
+ last;
}
- $items->reset;
- $seen++;
+ return ( 0, "on_reserve" ) unless $fillable;
}
+
+ } else {
+ my ($status, $matched_reserve, $possible_reserves) = CheckReserves($itemnumber);
+ return ( 0, "on_reserve" ) if $status;
}
}
- return ( 0, "on_reserve" ) if $resfound; # '' when no hold was found
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);
if ( $soonest > dt_from_string() ){
$borrowernumber ||= $issue->borrowernumber;
if ( defined $datedue && ref $datedue ne 'DateTime' ) {
- carp 'Invalid date passed to AddRenewal.';
- return;
+ $datedue = dt_from_string($datedue, 'sql');
}
my $patron = Koha::Patrons->find( $borrowernumber ) or return; # FIXME Should do more than just return
rule_name => 'unseen_renewals_allowed'
}
);
- if (!$seen && $rule && $rule->rule_value) {
+ if (!$seen && $rule && looks_like_number($rule->rule_value)) {
$unseen_renewals++;
} else {
# If the renewal is seen, unseen should revert to 0
my $renewal = Koha::Checkouts::Renewal->new(
{
checkout_id => $issue->issue_id,
- renewer_id => C4::Context->userenv->{'number'},
+ renewer_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : undef,
seen => $seen,
interface => C4::Context->interface
}
);
}
-=head2 GetTransfers
-
- GetTransfers($itemnumber);
-
-=cut
-
-sub GetTransfers {
- my ($itemnumber) = @_;
-
- my $dbh = C4::Context->dbh;
-
- my $query = '
- SELECT datesent,
- frombranch,
- tobranch,
- branchtransfer_id,
- daterequested,
- reason
- FROM branchtransfers
- WHERE itemnumber = ?
- AND datearrived IS NULL
- AND datecancelled IS NULL
- ';
- my $sth = $dbh->prepare($query);
- $sth->execute($itemnumber);
- my @row = $sth->fetchrow_array();
- return @row;
-}
-
=head2 GetTransfersFromTo
@results = GetTransfersFromTo($frombranch,$tobranch);
my $loanlength =
GetLoanLength( $borrower->{'categorycode'}, $itemtype, $branch );
- my $length_key = ( $isrenewal and defined $loanlength->{renewalperiod} )
+ my $length_key = ( $isrenewal and defined $loanlength->{renewalperiod} and $loanlength->{renewalperiod} ne q{} )
? qq{renewalperiod}
: qq{issuelength};
if ( $item ) {
my $itemnumber = $item->itemnumber;
- my $issue = GetOpenIssue( $itemnumber );
+ my $issue = $item->checkout;
if ( $issue ) {
my $leave_item_lost = C4::Context->preference("BlockReturnOfLostItems") ? 1 : 0;
ModDateLastSeen( $itemnumber, $leave_item_lost );
MarkIssueReturned(
- $issue->{borrowernumber},
+ $issue->borrowernumber,
$itemnumber,
$operation->{timestamp},
);
return "Barcode not found.";
}
my $itemnumber = $item->itemnumber;
- my $issue = GetOpenIssue( $itemnumber );
+ my $issue = $item->checkout;
- if ( $issue and ( $issue->{borrowernumber} ne $patron->borrowernumber ) ) { # Item already issued to another patron mark it returned
+ if ( $issue and ( $issue->borrowernumber ne $patron->borrowernumber ) ) { # Item already issued to another patron mark it returned
MarkIssueReturned(
- $issue->{borrowernumber},
+ $issue->borrowernumber,
$itemnumber,
$operation->{timestamp},
);
itemnumber => $issue->itemnumber,
borrowernumber => $issue->borrowernumber,
amount => $amount,
- due => output_pref($datedue),
+ due => $datedue,
});
}
elsif ($return_date) {
itemnumber => $issue->itemnumber,
borrowernumber => $issue->borrowernumber,
amount => 0,
- due => output_pref($datedue),
+ due => $datedue,
});
}
}