use strict;
#use warnings; FIXME - Bug 2505
+use DateTime;
use C4::Context;
use C4::Stats;
use C4::Reserves;
use C4::Items;
use C4::Members;
use C4::Dates;
-use C4::Calendar;
+use C4::Dates qw(format_date);
use C4::Accounts;
use C4::ItemCirculationAlertPreference;
-use C4::Dates qw(format_date);
use C4::Message;
use C4::Debug;
-use Date::Calc qw(
- Today
- Today_and_Now
- Add_Delta_YM
- Add_Delta_DHMS
- Date_to_Days
- Day_of_Week
- Add_Delta_Days
- check_date
- Delta_Days
-);
-use POSIX qw(strftime);
use C4::Branch; # GetBranches
use C4::Log; # logaction
use Data::Dumper;
use Koha::DateUtils;
+use Koha::Calendar;
+use Carp;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
my $branch_borrower_circ_rule = GetBranchBorrowerCircRule($branch, $cat_borrower);
if (defined($branch_borrower_circ_rule->{maxissueqty})) {
my @bind_params = ();
- my $branch_count_query = "SELECT COUNT(*) FROM issues
+ my $branch_count_query = "SELECT COUNT(*) FROM issues
JOIN items USING (itemnumber)
WHERE borrowernumber = ? ";
push @bind_params, $borrower->{borrowernumber};
if ($duedate && ref $duedate ne 'DateTime') {
$duedate = dt_from_string($duedate);
}
- my $now = DateTime->now( timezone => C4::Context->tz() );
+ my $now = DateTime->now( time_zone => C4::Context->tz() );
unless ( $duedate ) {
my $issuedate = $now->clone();
#
my ($current_loan_count, $max_loans_allowed) = TooMany( $borrower, $item->{biblionumber}, $item );
# if TooMany max_loans_allowed returns 0 the user doesn't have permission to check out this book
- if ($max_loans_allowed eq 0) {
+ if (defined $max_loans_allowed && $max_loans_allowed == 0) {
$needsconfirmation{PATRON_CANT} = 1;
} else {
if($max_loans_allowed){
# check if we just renew the issue.
#
if ($actualissue->{borrowernumber} eq $borrower->{'borrowernumber'}) {
- $datedue = AddRenewal(
- $borrower->{'borrowernumber'},
- $item->{'itemnumber'},
- $branch,
- $datedue,
- $issuedate, # here interpreted as the renewal date
+ $datedue = AddRenewal(
+ $borrower->{'borrowernumber'},
+ $item->{'itemnumber'},
+ $branch,
+ $datedue,
+ $issuedate, # here interpreted as the renewal date
);
}
else {
}
MoveReserve( $item->{'itemnumber'}, $borrower->{'borrowernumber'}, $cancelreserve );
-
# Starting process for transfer job (checking transfert and validate it if we have one)
my ($datesent) = GetTransfers($item->{'itemnumber'});
if ($datesent) {
# Record in the database the fact that the book was issued.
my $sth =
$dbh->prepare(
- "INSERT INTO issues
+ "INSERT INTO issues
(borrowernumber, itemnumber,issuedate, date_due, branchcode)
VALUES (?,?,?,?,?)"
);
ModItem({ issues => $item->{'issues'},
holdingbranch => C4::Context->userenv->{'branch'},
itemlost => 0,
- datelastborrowed => C4::Dates->new()->output('iso'),
+ datelastborrowed => DateTime->now(time_zone => C4::Context->tz())->ymd(),
onloan => $datedue->ymd(),
}, $item->{'biblionumber'}, $item->{'itemnumber'});
ModDateLastSeen( $item->{'itemnumber'} );
Retrieves circulation rule attributes that apply to the given
branch and item type, regardless of patron category.
-The return value is a hashref containing the following key:
+The return value is a hashref containing the following keys:
holdallowed => Hold policy for this branch and itemtype. Possible values:
0: No holds allowed.
1: Holds allowed only by patrons that have the same homebranch as the item.
2: Holds allowed from any patron.
+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
+
This searches branchitemrules in the following order:
* Same branchcode and itemtype
* branchcode '*', same itemtype
* branchcode and itemtype '*'
-Neither C<$branchcode> nor C<$categorycode> should be '*'.
+Neither C<$branchcode> nor C<$itemtype> should be '*'.
=cut
my $result = {};
my @attempts = (
- ['SELECT holdallowed
+ ['SELECT holdallowed, returnbranch
FROM branch_item_rules
WHERE branchcode = ?
AND itemtype = ?', $branchcode, $itemtype],
- ['SELECT holdallowed
+ ['SELECT holdallowed, returnbranch
FROM default_branch_circ_rules
WHERE branchcode = ?', $branchcode],
- ['SELECT holdallowed
+ ['SELECT holdallowed, returnbranch
FROM default_branch_item_rules
WHERE itemtype = ?', $itemtype],
- ['SELECT holdallowed
+ ['SELECT holdallowed, returnbranch
FROM default_circ_rules'],
);
foreach my $attempt (@attempts) {
my ($query, @bind_params) = @{$attempt};
+ my $search_result = $dbh->selectrow_hashref ( $query , {}, @bind_params );
# 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
- return $result if ( defined( $result->{'holdallowed'} = $dbh->selectrow_array( $query, {}, @bind_params ) ) );
+ $result->{'holdallowed'} = $search_result->{'holdallowed'} unless ( defined $result->{'holdallowed'} );
+ $result->{'returnbranch'} = $search_result->{'returnbranch'} unless ( defined $result->{'returnbranch'} );
}
# built-in default circulation rule
- return {
- holdallowed => 2,
- };
+ $result->{'holdallowed'} = 2 unless ( defined $result->{'holdallowed'} );
+ $result->{'returnbranch'} = 'homebranch' unless ( defined $result->{'returnbranch'} );
+
+ return $result;
}
=head2 AddReturn
my $item = GetItem($itemnumber) or die "GetItem($itemnumber) failed";
# full item data, but no borrowernumber or checkout info (no issue)
# we know GetItem should work because GetItemnumberFromBarcode worked
- my $hbr = C4::Context->preference("HomeOrHoldingBranchReturn") || "homebranch";
- $hbr = $item->{$hbr} || '';
- # item must be from items table -- issues table has branchcode and issuingbranch, not homebranch nor holdingbranch
+ my $hbr = GetBranchItemRule($item->{'homebranch'}, $item->{'itype'})->{'returnbranch'} || "homebranch";
+ # get the proper branch to which to return the item
+ $hbr = $item->{$hbr} || $branch ;
+ # if $hbr was "noreturn" or any other non-item table value, then it should 'float' (i.e. stay at this branch)
my $borrowernumber = $borrower->{'borrowernumber'} || undef; # we don't know if we had a borrower or not
# define circControlBranch only if dropbox mode is set
# don't allow dropbox mode to create an invalid entry in issues (issuedate > today)
# FIXME: check issuedate > returndate, factoring in holidays
- $circControlBranch = _GetCircControlBranch($item,$borrower) unless ( $item->{'issuedate'} eq C4::Dates->today('iso') );;
+ #$circControlBranch = _GetCircControlBranch($item,$borrower) unless ( $item->{'issuedate'} eq C4::Dates->today('iso') );;
+ $circControlBranch = _GetCircControlBranch($item,$borrower);
}
if ($borrowernumber) {
sub MarkIssueReturned {
my ( $borrowernumber, $itemnumber, $dropbox_branch, $returndate, $privacy ) = @_;
my $dbh = C4::Context->dbh;
- my $query = "UPDATE issues SET returndate=";
+ my $query = 'UPDATE issues SET returndate=';
my @bind;
if ($dropbox_branch) {
- my $calendar = C4::Calendar->new( branchcode => $dropbox_branch );
- my $dropboxdate = $calendar->addDate( C4::Dates->new(), -1 );
- $query .= " ? ";
- push @bind, $dropboxdate->output('iso');
+ my $calendar = Koha::Calendar->new( branchcode => $dropbox_branch );
+ my $dropboxdate = $calendar->addDate( DateTime->now( time_zone => C4::Context->tz), -1 );
+ $query .= ' ? ';
+ push @bind, $dropboxdate->strftime('%Y-%m-%d %H:%M');
} elsif ($returndate) {
- $query .= " ? ";
+ $query .= ' ? ';
push @bind, $returndate;
} else {
- $query .= " now() ";
+ $query .= ' now() ';
}
- $query .= " WHERE borrowernumber = ? AND itemnumber = ?";
+ $query .= ' WHERE borrowernumber = ? AND itemnumber = ?';
push @bind, $borrowernumber, $itemnumber;
# FIXME transaction
my $sth_upd = $dbh->prepare($query);
$sth_upd->execute(@bind);
- my $sth_copy = $dbh->prepare("INSERT INTO old_issues SELECT * FROM issues
+ my $sth_copy = $dbh->prepare('INSERT INTO old_issues SELECT * FROM issues
WHERE borrowernumber = ?
- AND itemnumber = ?");
+ AND itemnumber = ?');
$sth_copy->execute($borrowernumber, $itemnumber);
# anonymise patron checkout immediately if $privacy set to 2 and AnonymousPatron is set to a valid borrowernumber
if ( $privacy == 2) {
sub _FixFineDaysOnReturn {
my ( $borrower, $item, $datedue ) = @_;
-
- if ($datedue) {
- $datedue = C4::Dates->new( $datedue, "iso" );
- } else {
- return;
- }
+ return unless ($datedue);
+
+ my $dt_due = dt_from_string( $datedue );
+ my $dt_today = DateTime->now( time_zone => C4::Context->tz() );
my $branchcode = _GetCircControlBranch( $item, $borrower );
- my $calendar = C4::Calendar->new( branchcode => $branchcode );
- my $today = C4::Dates->new();
+ my $calendar = Koha::Calendar->new( branchcode => $branchcode );
- my $deltadays = $calendar->daysBetween( $datedue, C4::Dates->new() );
+ # $deltadays is a DateTime::Duration object
+ my $deltadays = $calendar->days_between( $dt_due, $dt_today );
my $circcontrol = C4::Context::preference('CircControl');
my $issuingrule = GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode );
# exit if no finedays defined
return unless $finedays;
- my $grace = $issuingrule->{firstremind};
-
- if ( $deltadays - $grace > 0 ) {
- my @newdate = Add_Delta_Days( Today(), $deltadays * $finedays );
- my $isonewdate = join( '-', @newdate );
- my ( $deby, $debm, $debd ) = split( /-/, $borrower->{debarred} );
- if ( check_date( $deby, $debm, $debd ) ) {
- my @olddate = split( /-/, $borrower->{debarred} );
-
- if ( Delta_Days( @olddate, @newdate ) > 0 ) {
- C4::Members::DebarMember( $borrower->{borrowernumber}, $isonewdate );
- return $isonewdate;
+ my $grace = DateTime::Duration->new( days => $issuingrule->{firstremind} );
+
+ if ( ( $deltadays - $grace )->is_positive ) { # you can't compare DateTime::Durations with logical operators
+ my $new_debar_dt = $dt_today->clone()->add_duration( $deltadays * $finedays );
+ my $borrower_debar_dt = dt_from_string( $borrower->{debarred} );
+ # check to see if the current debar date is a valid date
+ if ( $borrower->{debarred} && $borrower_debar_dt ) {
+ # if so, is it before the new date? update only if true
+ if ( DateTime->compare( $borrower_debar_dt, $new_debar_dt ) == -1 ) {
+ C4::Members::DebarMember( $borrower->{borrowernumber}, $new_debar_dt->ymd() );
+ return $new_debar_dt->ymd();
}
+ # if the borrower's debar date is not set or valid, debar them
} else {
- C4::Members::DebarMember( $borrower->{borrowernumber}, $isonewdate );
- return $isonewdate;
+ C4::Members::DebarMember( $borrower->{borrowernumber}, $new_debar_dt->ymd() );
+ return $new_debar_dt->ymd();
}
}
}
return unless $itemnumber;
my $sth = C4::Context->dbh->prepare(
"SELECT *
- FROM issues
+ FROM issues
LEFT JOIN items ON issues.itemnumber=items.itemnumber
WHERE issues.itemnumber=?");
$sth->execute($itemnumber);
my $data = $sth->fetchrow_hashref;
return unless $data;
- $data->{'overdue'} = ($data->{'date_due'} lt C4::Dates->today('iso')) ? 1 : 0;
- return ($data);
+ $data->{issuedate} = dt_from_string($data->{issuedate}, 'sql');
+ $data->{issuedate}->truncate(to => 'minutes');
+ $data->{date_due} = dt_from_string($data->{date_due}, 'sql');
+ $data->{date_due}->truncate(to => 'minutes');
+ my $dt = DateTime->now( time_zone => C4::Context->tz)->truncate( to => 'minutes');
+ $data->{'overdue'} = DateTime->compare($data->{'date_due'}, $dt ) == -1 ? 1 : 0;
+ return $data;
}
=head2 GetOpenIssue
sub GetItemIssues {
my ( $itemnumber, $history ) = @_;
- my $today = C4::Dates->today('iso'); # get today date
- my $sql = "SELECT * FROM issues
+ my $today = DateTime->now( time_zome => C4::Context->tz); # get today date
+ $today->truncate( to => 'minutes' );
+ my $sql = "SELECT * FROM issues
JOIN borrowers USING (borrowernumber)
JOIN items USING (itemnumber)
WHERE issues.itemnumber = ? ";
if ($history) {
$sql .= "UNION ALL
- SELECT * FROM old_issues
+ SELECT * FROM old_issues
LEFT JOIN borrowers USING (borrowernumber)
JOIN items USING (itemnumber)
WHERE old_issues.itemnumber = ? ";
}
my $results = $sth->fetchall_arrayref({});
foreach (@$results) {
- $_->{'overdue'} = ($_->{'date_due'} lt $today) ? 1 : 0;
+ my $date_due = dt_from_string($_->{date_due},'sql');
+ $date_due->truncate( to => 'minutes' );
+
+ $_->{overdue} = (DateTime->compare($date_due, $today) == -1) ? 1 : 0;
}
return $results;
}
SELECT
borrowers.categorycode, biblioitems.itemtype, issues.renewals, renewalsallowed, $controlbranch
FROM issuingrules,
- issues
+ issues
LEFT JOIN items USING (itemnumber)
LEFT JOIN borrowers USING (borrowernumber)
LEFT JOIN biblioitems USING (biblioitemnumber)
my $itemnumber = shift or return undef;
my $branch = shift;
my $datedue = shift;
- my $lastreneweddate = shift || C4::Dates->new()->output('iso');
+ 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;
$sth->execute( $borrowernumber, $itemnumber );
my $issuedata = $sth->fetchrow_hashref;
$sth->finish;
- if($datedue && ! $datedue->output('iso')){
- warn "Invalid date passed to AddRenewal.";
- return undef;
+ if(defined $datedue && ref $datedue ne 'DateTime' ) {
+ carp 'Invalid date passed to AddRenewal.';
+ return;
}
# 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
my $itemtype = (C4::Context->preference('item-level_itypes')) ? $biblio->{'itype'} : $biblio->{'itemtype'};
$datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ?
- C4::Dates->new($issuedata->{date_due}, 'iso') :
- C4::Dates->new();
+ $issuedata->{date_due} :
+ DateTime->now( time_zone => C4::Context->tz());
$datedue = CalcDateDue($datedue,$itemtype,$issuedata->{'branchcode'},$borrower);
}
WHERE borrowernumber=?
AND itemnumber=?"
);
- $sth->execute( $datedue->output('iso'), $renews, $lastreneweddate, $borrowernumber, $itemnumber );
+
+ $sth->execute( $datedue->strftime('%Y-%m-%d %H:%M'), $renews, $lastreneweddate, $borrowernumber, $itemnumber );
$sth->finish;
# Update the renewal count on the item, and tell zebra to reindex
$renews = $biblio->{'renewals'} + 1;
- ModItem({ renewals => $renews, onloan => $datedue->output('iso') }, $biblio->{'biblionumber'}, $itemnumber);
+ ModItem({ renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M')}, $biblio->{'biblionumber'}, $itemnumber);
# Charge a new rental fee, if applicable?
my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
$sth->execute( $borrowernumber, $accountno, $charge, $manager_id,
"Renewal of Rental Item $item->{'title'} $item->{'barcode'}",
'Rent', $charge, $itemnumber );
- $sth->finish;
}
# Log the renewal
UpdateStats( $branch, 'renew', $charge, '', $itemnumber, $item->{itype}, $borrowernumber);
}
my $calendar = Koha::Calendar->new( branchcode => $branch );
$datedue = $calendar->addDate( $startdate, $dur, $loanlength->{lengthunit} );
+ if ($loanlength->{lengthunit} eq 'days') {
+ $datedue->set_hour(23);
+ $datedue->set_minute(59);
+ }
}
}
return $datedue;
}
-=head2 CheckValidDatedue
-
- $newdatedue = CheckValidDatedue($date_due,$itemnumber,$branchcode);
-
-This function does not account for holiday exceptions nor does it handle the 'useDaysMode' syspref .
-To be replaced by CalcDateDue() once C4::Calendar use is tested.
-
-this function validates the loan length against the holidays calendar, and adjusts the due date as per the 'useDaysMode' syspref.
-C<$date_due> = returndate calculate with no day check
-C<$itemnumber> = itemnumber
-C<$branchcode> = location of issue (affected by 'CircControl' syspref)
-C<$loanlength> = loan length prior to adjustment
-
-=cut
-
-sub CheckValidDatedue {
-my ($date_due,$itemnumber,$branchcode)=@_;
-my @datedue=split('-',$date_due->output('iso'));
-my $years=$datedue[0];
-my $month=$datedue[1];
-my $day=$datedue[2];
-# die "Item# $itemnumber ($branchcode) due: " . ${date_due}->output() . "\n(Y,M,D) = ($years,$month,$day)":
-my $dow;
-for (my $i=0;$i<2;$i++){
- $dow=Day_of_Week($years,$month,$day);
- ($dow=0) if ($dow>6);
- my $result=CheckRepeatableHolidays($itemnumber,$dow,$branchcode);
- my $countspecial=CheckSpecialHolidays($years,$month,$day,$itemnumber,$branchcode);
- my $countspecialrepeatable=CheckRepeatableSpecialHolidays($month,$day,$itemnumber,$branchcode);
- if (($result ne '0') or ($countspecial ne '0') or ($countspecialrepeatable ne '0') ){
- $i=0;
- (($years,$month,$day) = Add_Delta_Days($years,$month,$day, 1))if ($i ne '1');
- }
- }
- my $newdatedue=C4::Dates->new(sprintf("%04d-%02d-%02d",$years,$month,$day),'iso');
-return $newdatedue;
-}
-
=head2 CheckRepeatableHolidays