use C4::Reserves;
use C4::Koha;
use C4::Biblio;
+use C4::Items;
use C4::Members;
use C4::Dates;
+use C4::Calendar;
+use C4::Accounts;
use Date::Calc qw(
Today
Today_and_Now
use Data::Dumper;
-our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,%EXPORT_TAGS);
-
-# set the version for version checking
-$VERSION = 3.00;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+BEGIN {
+ # set the version for version checking
+ $VERSION = 3.01;
+ @ISA = qw(Exporter);
+
+ # FIXME subs that should probably be elsewhere
+ push @EXPORT, qw(
+ &FixOverduesOnReturn
+ &barcodedecode
+ );
+
+ # subs to deal with issuing a book
+ push @EXPORT, qw(
+ &CanBookBeIssued
+ &CanBookBeRenewed
+ &AddIssue
+ &AddRenewal
+ &GetRenewCount
+ &GetItemIssue
+ &GetItemIssues
+ &GetBorrowerIssues
+ &GetIssuingCharges
+ &GetBiblioIssues
+ &AnonymiseIssueHistory
+ );
+
+ # subs to deal with returns
+ push @EXPORT, qw(
+ &AddReturn
+ &MarkIssueReturned
+ );
+
+ # subs to deal with transfers
+ push @EXPORT, qw(
+ &transferbook
+ &GetTransfers
+ &GetTransfersFromTo
+ &updateWrongTransfer
+ &DeleteTransfer
+ );
+}
=head1 NAME
=head1 FUNCTIONS
-=cut
-
-@ISA = qw(Exporter);
-
-# FIXME subs that should probably be elsewhere
-push @EXPORT, qw(
- &FixOverduesOnReturn
- &cuecatbarcodedecode
-);
-
-# subs to deal with issuing a book
-push @EXPORT, qw(
- &CanBookBeIssued
- &CanBookBeRenewed
- &AddIssue
- &AddRenewal
- &GetRenewCount
- &GetItemIssue
- &GetItemIssues
- &GetBorrowerIssues
- &GetIssuingCharges
- &GetBiblioIssues
- &AnonymiseIssueHistory
-);
-# subs to deal with returns
-push @EXPORT, qw(
- &AddReturn
-);
-
-# subs to deal with transfers
-push @EXPORT, qw(
- &transferbook
- &GetTransfers
- &GetTransfersFromTo
- &updateWrongTransfer
- &DeleteTransfer
-);
-
-# FIXME - At least, I'm pretty sure this is for decoding CueCat stuff.
-# FIXME From Paul : i don't understand what this sub does & why it has to be called on every circ. Speak of this with chris maybe ?
-
=head2 decode
=head3 $str = &decode($chunk);
=over 4
-=item Decodes a segment of a string emitted by a CueCat barcode scanner and
-returns it.
+=item Generic filter function for barcode string.
=back
=cut
-sub cuecatbarcodedecode {
+# FIXME From Paul : i don't understand what this sub does & why it has to be called on every circ. Speak of this with chris maybe ?
+# FIXME -- the &decode fcn below should be wrapped into this one.
+
+sub barcodedecode {
my ($barcode) = @_;
- chomp($barcode);
- my @fields = split( /\./, $barcode );
- my @results = map( decode($_), @fields[ 1 .. $#fields ] );
- if ( $#results == 2 ) {
- return $results[2];
- }
- else {
- return $barcode;
- }
+ my $filter = C4::Context->preference('itemBarcodeInputFilter');
+ if($filter eq 'whitespace') {
+ $barcode =~ s/\s//g;
+ return $barcode;
+ } elsif($filter eq 'cuecat') {
+ chomp($barcode);
+ my @fields = split( /\./, $barcode );
+ my @results = map( decode($_), @fields[ 1 .. $#fields ] );
+ if ( $#results == 2 ) {
+ return $results[2];
+ }
+ else {
+ return $barcode;
+ }
+ } elsif($filter eq 'T-prefix') {
+ my $num = ( $barcode =~ /^[Tt] /) ? substr($barcode,2) + 0 : $barcode;
+ return sprintf( "T%07d",$num);
+ }
}
=head2 decode
my $dbh = C4::Context->dbh;
my $branch;
# Get which branchcode we need
- if (C4::Context->preference('CircControl') eq 'PickupLibary'){
- $branch = C4::Context->userenv->{'branchcode'};
+ if (C4::Context->preference('CircControl') eq 'PickupLibrary'){
+ $branch = C4::Context->userenv->{'branch'};
}
- elsif (C4::Context->preference('CircControl') eq 'PatronLibary'){
+ elsif (C4::Context->preference('CircControl') eq 'PatronLibrary'){
$branch = $borrower->{'branchcode'};
}
else {
my $query2 = "SELECT COUNT(*) FROM issues i, biblioitems s1, items s2
WHERE i.borrowernumber = ?
- AND i.returndate IS NULL
AND i.itemnumber = s2.itemnumber
AND s1.biblioitemnumber = s2.biblioitemnumber";
if (C4::Context->preference('item-level_itypes')){
my $sth3 =
$dbh->prepare(
'SELECT COUNT(*) FROM issues
- WHERE borrowernumber = ?
- AND returndate IS NULL'
+ WHERE borrowernumber = ?'
);
my $alreadyissued;
return ( "$alreadyissued / ".( $result->{maxissueqty} + 0 )." (rule on branch/category/itemtype failed)" );
}
# now checking for total
- $sth->execute( $cat_borrower, '', $branch );
+ $sth->execute( $cat_borrower, '*', $branch );
my $result = $sth->fetchrow_hashref;
- if ( $result->{maxissueqty} ne '*' ) {
+ if ( $result->{maxissueqty} ne '' ) {
$sth2->execute( $borrower->{'borrowernumber'}, $type );
my $alreadyissued = $sth2->fetchrow;
if ( $result->{'maxissueqty'} <= $alreadyissued ) {
# check the 2 parameters (branch / itemtype / default categorycode
$sth->execute( '*', $type, $branch );
- my $result = $sth->fetchrow_hashref;
+ $result = $sth->fetchrow_hashref;
# warn "*, $type, $branch = ".Data::Dumper::Dumper($result);
if ( $result->{maxissueqty} ne '' ) {
# check the 1 parameters (default branch / itemtype / categorycode
$sth->execute( $cat_borrower, $type, '*' );
- my $result = $sth->fetchrow_hashref;
+ $result = $sth->fetchrow_hashref;
# warn "$cat_borrower, $type, * = ".Data::Dumper::Dumper($result);
if ( $result->{maxissueqty} ne '' ) {
# check the 0 parameters (default branch / itemtype / default categorycode
$sth->execute( '*', $type, '*' );
- my $result = $sth->fetchrow_hashref;
+ $result = $sth->fetchrow_hashref;
# warn "*, $type, * = ".Data::Dumper::Dumper($result);
if ( $result->{maxissueqty} ne '' ) {
}
# now checking for total
$sth->execute( '*', '*', '*' );
- my $result = $sth->fetchrow_hashref;
+ $result = $sth->fetchrow_hashref;
if ( $result->{maxissueqty} ne '' ) {
warn "checking total";
$sth2->execute( $borrower->{'borrowernumber'}, $type );
sub itemissues {
my ( $bibitem, $biblio ) = @_;
my $dbh = C4::Context->dbh;
-
- # FIXME - If this function die()s, the script will abort, and the
- # user won't get anything; depending on how far the script has
- # gotten, the user might get a blank page. It would be much better
- # to at least print an error message. The easiest way to do this
- # is to set $SIG{__DIE__}.
my $sth =
$dbh->prepare("Select * from items where items.biblioitemnumber = ?")
|| die $dbh->errstr;
"SELECT * FROM issues
LEFT JOIN borrowers ON issues.borrowernumber = borrowers.borrowernumber
WHERE itemnumber = ?
- AND returndate IS NULL
"
);
$data->{'borrower'} = $data2->{'borrowernumber'};
}
else {
- if ( $data->{'wthdrawn'} eq '1' ) {
- $data->{'date_due'} = 'Cancelled';
- }
- else {
- $data->{'date_due'} = 'Available';
- } # else
- } # else
+ $data->{'date_due'} = ($data->{'wthdrawn'} eq '1') ? 'Cancelled' : 'Available';
+ }
$sth2->finish;
# Find the last 3 people who borrowed this item.
$sth2 = $dbh->prepare(
- "SELECT * FROM issues
+ "SELECT * FROM old_issues
LEFT JOIN borrowers ON issues.borrowernumber = borrowers.borrowernumber
WHERE itemnumber = ?
- AND returndate IS NOT NULL
ORDER BY returndate DESC,timestamp DESC"
);
=head2 CanBookBeIssued
-$issuingimpossible, $needsconfirmation =
+( $issuingimpossible, $needsconfirmation ) =
CanBookBeIssued( $borrower, $barcode, $duedatespec, $inprocess );
C<$duedatespec> is a C4::Dates object.
C<$issuingimpossible> and C<$needsconfirmation> are some hashref.
my $item = GetItem(GetItemnumberFromBarcode( $barcode ));
my $issue = GetItemIssue($item->{itemnumber});
my $biblioitem = GetBiblioItemData($item->{biblioitemnumber});
- $item->{'itemtype'}=$biblioitem->{'itemtype'};
+ $item->{'itemtype'}=$item->{'itype'};
my $dbh = C4::Context->dbh;
#
#
# BORROWER STATUS
#
+ if ( $borrower->{'category_type'} eq 'X' && ( $item->{barcode} )) {
+ # stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1 .
+ &UpdateStats(C4::Context->userenv->{'branch'},'localuse','','',$item->{'itemnumber'},$item->{'itemtype'},$borrower->{'borrowernumber'});
+ return( { STATS => 1 }, {});
+ }
if ( $borrower->{flags}->{GNA} ) {
$issuingimpossible{GNA} = 1;
}
my $userenv = C4::Context->userenv;
if ( ($userenv) && ( $userenv->{flags} != 1 ) ) {
$issuingimpossible{NOTSAMEBRANCH} = 1
- if ( $item->{C4::Context->preference("HomeOrHoldingbranch")} ne $userenv->{branch} );
+ if ( $item->{C4::Context->preference("HomeOrHoldingBranch")} ne $userenv->{branch} );
}
}
# Already issued to current borrower. Ask whether the loan should
# be renewed.
- my ($CanBookBeRenewed) = CanBookBeRenewed(
+ my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed(
$borrower->{'borrowernumber'},
$item->{'itemnumber'}
);
# See if the item is on reserve.
my ( $restype, $res ) = C4::Reserves::CheckReserves( $item->{'itemnumber'} );
if ($restype) {
- my $resbor = $res->{'borrowernumber'};
+ my $resbor = $res->{'borrowernumber'};
+ my ( $resborrower, $flags ) = GetMemberDetails( $resbor, 0 );
+ my $branches = GetBranches();
+ my $branchname = $branches->{ $res->{'branchcode'} }->{'branchname'};
if ( $resbor ne $borrower->{'borrowernumber'} && $restype eq "Waiting" )
{
-
# The item is on reserve and waiting, but has been
# reserved by some other patron.
- my ( $resborrower, $flags ) =
- GetMemberDetails( $resbor, 0 );
- my $branches = GetBranches();
- my $branchname =
- $branches->{ $res->{'branchcode'} }->{'branchname'};
$needsconfirmation{RESERVE_WAITING} =
"$resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'}, $branchname)";
-
-# CancelReserve(0, $res->{'itemnumber'}, $res->{'borrowernumber'}); Doesn't belong in a checking subroutine.
}
elsif ( $restype eq "Reserved" ) {
-
# The item is on reserve for someone else.
- my ( $resborrower, $flags ) =
- GetMemberDetails( $resbor, 0 );
- my $branches = GetBranches();
- my $branchname =
- $branches->{ $res->{'branchcode'} }->{'branchname'};
$needsconfirmation{RESERVED} =
"$res->{'reservedate'} : $resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'})";
}
}
if ( C4::Context->preference("LibraryName") eq "Horowhenua Library Trust" ) {
if ( $borrower->{'categorycode'} eq 'W' ) {
- my %issuingimpossible;
- return ( \%issuingimpossible, \%needsconfirmation );
- } else {
- return ( \%issuingimpossible, \%needsconfirmation );
+ my %emptyhash;
+ return ( \%emptyhash, \%needsconfirmation );
}
- } else {
- return ( \%issuingimpossible, \%needsconfirmation );
- }
+ }
+ return ( \%issuingimpossible, \%needsconfirmation );
}
=head2 AddIssue
my $branch;
# Get which branchcode we need
- if (C4::Context->preference('CircControl') eq 'PickupLibary'){
- $branch = C4::Context->userenv->{'branchcode'};
+ if (C4::Context->preference('CircControl') eq 'PickupLibrary'){
+ $branch = C4::Context->userenv->{'branch'};
}
- elsif (C4::Context->preference('CircControl') eq 'PatronLibary'){
+ elsif (C4::Context->preference('CircControl') eq 'PatronLibrary'){
$branch = $borrower->{'branchcode'};
}
else {
"UPDATE branchtransfers
SET datearrived = now(),
tobranch = ?,
- comments = 'Forced branchtransfert'
+ comments = 'Forced branchtransfer'
WHERE itemnumber= ? AND datearrived IS NULL"
);
$sth->execute(C4::Context->userenv->{'branch'},$item->{'itemnumber'});
$itype,
$branch
);
- $datedue = time + ($loanlength) * 86400;
- my @datearr = localtime($datedue);
- $dateduef = C4::Dates->new( sprintf("%04d-%02d-%02d", 1900 + $datearr[5], $datearr[4] + 1, $datearr[3]), 'iso');
- $dateduef=CheckValidDatedue($dateduef,$item->{'itemnumber'},C4::Context->userenv->{'branch'});
-
+ $dateduef = CalcDateDue(C4::Dates->new(),$loanlength,$branch);
# if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate
if ( C4::Context->preference('ReturnBeforeExpiry') && $dateduef->output('iso') gt $borrower->{dateexpiry} ) {
$dateduef = C4::Dates->new($borrower->{dateexpiry},'iso');
);
$sth->finish;
$item->{'issues'}++;
- $sth =
- $dbh->prepare(
- "UPDATE items SET issues=?, holdingbranch=?, itemlost=0, datelastborrowed = now(), onloan = ? WHERE itemnumber=?");
- $sth->execute(
- $item->{'issues'},
- C4::Context->userenv->{'branch'},
- $dateduef->output('iso'),
- $item->{'itemnumber'}
- );
- $sth->finish;
- &ModDateLastSeen( $item->{'itemnumber'} );
- my $record = GetMarcItem( $item->{'biblionumber'}, $item->{'itemnumber'} );
- my $frameworkcode = GetFrameworkCode( $item->{'biblionumber'} );
- ModItemInMarc( $record, $item->{'biblionumber'}, $item->{'itemnumber'}, $frameworkcode );
+ ModItem({ issues => $item->{'issues'},
+ holdingbranch => C4::Context->userenv->{'branch'},
+ itemlost => 0,
+ datelastborrowed => C4::Dates->new()->output('iso'),
+ onloan => $dateduef->output('iso'),
+ }, $item->{'biblionumber'}, $item->{'itemnumber'});
+ ModDateLastSeen( $item->{'itemnumber'} );
+
# If it costs to borrow this book, charge it to the patron's account.
my ( $charge, $itemtype ) = GetIssuingCharges(
$item->{'itemnumber'},
);
}
- &logaction(C4::Context->userenv->{'number'},"CIRCULATION","ISSUE",$borrower->{'borrowernumber'},$biblio->{'biblionumber'})
+ logaction("CIRCULATION", "ISSUE", $borrower->{'borrowernumber'}, $biblio->{'biblionumber'})
if C4::Context->preference("IssueLog");
return ($datedue);
}
# get information on item
my $iteminformation = GetItemIssue( GetItemnumberFromBarcode($barcode));
- my $biblio = GetBiblioFromItemNumber($iteminformation->{'itemnumber'});
+ my $biblio = GetBiblioItemData($iteminformation->{'biblioitemnumber'});
+# use Data::Dumper;warn Data::Dumper::Dumper($iteminformation);
unless ($iteminformation->{'itemnumber'} ) {
$messages->{'BadBarcode'} = $barcode;
$doreturn = 0;
# find the borrower
if ( ( not $iteminformation->{borrowernumber} ) && $doreturn ) {
$messages->{'NotIssued'} = $barcode;
+ # even though item is not on loan, it may still
+ # be transferred; therefore, get current branch information
+ my $curr_iteminfo = GetItem($iteminformation->{'itemnumber'});
+ $iteminformation->{'homebranch'} = $curr_iteminfo->{'homebranch'};
+ $iteminformation->{'holdingbranch'} = $curr_iteminfo->{'holdingbranch'};
$doreturn = 0;
}
$messages->{'IsPermanent'} = $hbr;
}
- # if independent branches are on and returning to different branch, refuse the return
+ # if independent branches are on and returning to different branch, refuse the return
if ($hbr ne C4::Context->userenv->{'branch'} && C4::Context->preference("IndependantBranches")){
- $messages->{'Wrongbranch'} = 1;
- $doreturn=0;
- }
+ $messages->{'Wrongbranch'} = 1;
+ $doreturn=0;
+ }
# check that the book has been cancelled
if ( $iteminformation->{'wthdrawn'} ) {
# case of a return of document (deal with issues and holdingbranch)
if ($doreturn) {
- my $sth =
- $dbh->prepare(
- "UPDATE issues SET returndate = now() WHERE (borrowernumber = ?) AND (itemnumber = ?) AND (returndate IS NULL)"
- );
- $sth->execute( $borrower->{'borrowernumber'},
- $iteminformation->{'itemnumber'} );
+ MarkIssueReturned($borrower->{'borrowernumber'}, $iteminformation->{'itemnumber'});
$messages->{'WasReturned'} = 1; # FIXME is the "= 1" right?
}
# continue to deal with returns cases, but not only if we have an issue
- # the holdingbranch is updated if the document is returned in an other location .
- if ( $iteminformation->{'holdingbranch'} ne C4::Context->userenv->{'branch'} ) {
- UpdateHoldingbranch(C4::Context->userenv->{'branch'},$iteminformation->{'itemnumber'});
- # reload iteminformation holdingbranch with the userenv value
- $iteminformation->{'holdingbranch'} = C4::Context->userenv->{'branch'};
- }
+ # the holdingbranch is updated if the document is returned in an other location .
+ if ( $iteminformation->{'holdingbranch'} ne C4::Context->userenv->{'branch'} ) {
+ UpdateHoldingbranch(C4::Context->userenv->{'branch'},$iteminformation->{'itemnumber'});
+ # reload iteminformation holdingbranch with the userenv value
+ $iteminformation->{'holdingbranch'} = C4::Context->userenv->{'branch'};
+ }
ModDateLastSeen( $iteminformation->{'itemnumber'} );
- my $sth = $dbh->prepare("UPDATE items SET onloan = NULL where itemnumber = ?");
- $sth->execute($iteminformation->{'itemnumber'});
- $sth->finish();
- my $record = GetMarcItem( $biblio->{'biblionumber'}, $iteminformation->{'itemnumber'} );
- my $frameworkcode = GetFrameworkCode( $biblio->{'biblionumber'} );
- ModItemInMarc( $record, $biblio->{'biblionumber'}, $iteminformation->{'itemnumber'}, $frameworkcode );
-
- if ($iteminformation->{borrowernumber}){
- ($borrower) = C4::Members::GetMemberDetails( $iteminformation->{borrowernumber}, 0 );
- }
+ ModItem({ onloan => undef }, $biblio->{'biblionumber'}, $iteminformation->{'itemnumber'});
+
+ if ($iteminformation->{borrowernumber}){
+ ($borrower) = C4::Members::GetMemberDetails( $iteminformation->{borrowernumber}, 0 );
+ }
# fix up the accounts.....
if ( $iteminformation->{'itemlost'} ) {
$messages->{'WasLost'} = 1;
UpdateStats(
$branch, 'return', '0', '',
$iteminformation->{'itemnumber'},
- $iteminformation->{'itemtype'},
+ $biblio->{'itemtype'},
$borrower->{'borrowernumber'}
);
- &logaction(C4::Context->userenv->{'number'},"CIRCULATION","RETURN",$iteminformation->{borrowernumber},$iteminformation->{'biblionumber'})
+ logaction("CIRCULATION", "RETURN", $iteminformation->{borrowernumber}, $iteminformation->{'biblionumber'})
if C4::Context->preference("ReturnLog");
#adding message if holdingbranch is non equal a userenv branch to return the document to homebranch
return ( $doreturn, $messages, $iteminformation, $borrower );
}
+=head2 MarkIssueReturned
+
+=over 4
+
+MarkIssueReturned($borrowernumber, $itemnumber);
+
+=back
+
+Unconditionally marks an issue as being returned by
+moving the C<issues> row to C<old_issues> and
+setting C<returndate> to the current date.
+
+Ideally, this function would be internal to C<C4::Circulation>,
+not exported, but it is currently needed by one
+routine in C<C4::Accounts>.
+
+=cut
+
+sub MarkIssueReturned {
+ my ($borrowernumber, $itemnumber) = @_;
+
+ my $dbh = C4::Context->dbh;
+ # FIXME transaction
+ my $sth_upd = $dbh->prepare("UPDATE issues SET returndate = now()
+ WHERE borrowernumber = ?
+ AND itemnumber = ?");
+ $sth_upd->execute($borrowernumber, $itemnumber);
+ my $sth_copy = $dbh->prepare("INSERT INTO old_issues SELECT * FROM issues
+ WHERE borrowernumber = ?
+ AND itemnumber = ?");
+ $sth_copy->execute($borrowernumber, $itemnumber);
+ my $sth_del = $dbh->prepare("DELETE FROM issues
+ WHERE borrowernumber = ?
+ AND itemnumber = ?");
+ $sth_del->execute($borrowernumber, $itemnumber);
+}
+
=head2 FixOverduesOnReturn
&FixOverduesOnReturn($brn,$itm, $exemptfine);
VALUES (?,?,?,?)");
$usth->execute($borrower->{'borrowernumber'},$data->{'accountno'},$nextaccntno,$offset);
$usth->finish;
- $usth = $dbh->prepare("UPDATE items SET paidfor='' WHERE itemnumber=?");
- $usth->execute($itm);
- $usth->finish;
+ ModItem({ paidfor => '' }, undef, $itm);
}
$sth->finish;
return;
C<$itemnumber> is the itemnumber
Returns an array of hashes
+
=cut
sub GetItemIssue {
"SELECT * FROM issues
LEFT JOIN items ON issues.itemnumber=items.itemnumber
WHERE
- issues.itemnumber=? AND returndate IS NULL ");
+ issues.itemnumber=?");
$sth->execute($itemnumber);
my $data = $sth->fetchrow_hashref;
my $datedue = $data->{'date_due'};
C<$history> is 0 if you want actuel "issuer" (if it exist) and 1 if you want issues history
Returns an array of hashes
+
=cut
sub GetItemIssues {
# get today date
my $today = POSIX::strftime("%Y%m%d", localtime);
- my $sth = $dbh->prepare(
- "SELECT * FROM issues
- LEFT JOIN borrowers ON borrowers.borrowernumber
- LEFT JOIN items ON items.itemnumber=issues.itemnumber
- WHERE
- issues.itemnumber=?".($history?"":" AND returndate IS NULL ").
- "ORDER BY issues.date_due DESC"
- );
- $sth->execute($itemnumber);
+ 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
+ LEFT JOIN borrowers USING (borrowernumber)
+ JOIN items USING (itemnumber)
+ WHERE old_issues.itemnumber = ? ";
+ }
+ $sql .= "ORDER BY date_due DESC";
+ my $sth = $dbh->prepare($sql);
+ if ($history) {
+ $sth->execute($itemnumber, $itemnumber);
+ } else {
+ $sth->execute($itemnumber);
+ }
while ( my $data = $sth->fetchrow_hashref ) {
my $datedue = $data->{'date_due'};
$datedue =~ s/-//g;
LEFT JOIN biblioitems ON items.itemnumber = biblioitems.biblioitemnumber
LEFT JOIN biblio ON biblio.biblionumber = items.biblioitemnumber
WHERE biblio.biblionumber = ?
- ORDER BY issues.timestamp
+ UNION ALL
+ SELECT old_issues.*,items.barcode,biblio.biblionumber,biblio.title, biblio.author,borrowers.cardnumber,borrowers.surname,borrowers.firstname
+ FROM old_issues
+ LEFT JOIN borrowers ON borrowers.borrowernumber = old_issues.borrowernumber
+ LEFT JOIN items ON old_issues.itemnumber = items.itemnumber
+ LEFT JOIN biblioitems ON items.itemnumber = biblioitems.biblioitemnumber
+ LEFT JOIN biblio ON biblio.biblionumber = items.biblioitemnumber
+ WHERE biblio.biblionumber = ?
+ ORDER BY timestamp
";
my $sth = $dbh->prepare($query);
- $sth->execute($biblionumber);
+ $sth->execute($biblionumber, $biblionumber);
my @issues;
while ( my $data = $sth->fetchrow_hashref ) {
=head2 CanBookBeRenewed
-$ok = &CanBookBeRenewed($borrowernumber, $itemnumber);
+($ok,$error) = &CanBookBeRenewed($borrowernumber, $itemnumber);
Find out whether a borrowed item may be renewed.
C<$CanBookBeRenewed> returns a true value iff the item may be renewed. The
item must currently be on loan to the specified borrower; renewals
must be allowed for the item's type; and the borrower must not have
-already renewed the loan.
+already renewed the loan. $error will contain the reason the renewal can not proceed
=cut
my $dbh = C4::Context->dbh;
my $renews = 1;
my $renewokay = 0;
+ my $error;
# Look in the issues table for this item, lent to this borrower,
# and not yet returned.
my $sth1 = $dbh->prepare(
"SELECT * FROM issues
WHERE borrowernumber = ?
- AND itemnumber = ?
- AND returndate IS NULL"
+ AND itemnumber = ?"
);
$sth1->execute( $borrowernumber, $itemnumber );
if ( my $data1 = $sth1->fetchrow_hashref ) {
# because it's a bit messy: given the item number, we need to find
# the biblioitem, which gives us the itemtype, which tells us
# whether it may be renewed.
- my $sth2 = $dbh->prepare(
- "SELECT renewalsallowed FROM items
- LEFT JOIN biblioitems on items.biblioitemnumber = biblioitems.biblioitemnumber
- LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
- WHERE items.itemnumber = ?
- "
- );
+ my $query = "SELECT renewalsallowed FROM items ";
+ $query .= (C4::Context->preference('item-level_itypes'))
+ ? "LEFT JOIN itemtypes ON items.itype = itemtypes.itemtype "
+ : "LEFT JOIN biblioitems on items.biblioitemnumber = biblioitems.biblioitemnumber
+ LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype ";
+ $query .= "WHERE items.itemnumber = ?";
+ my $sth2 = $dbh->prepare($query);
$sth2->execute($itemnumber);
if ( my $data2 = $sth2->fetchrow_hashref ) {
$renews = $data2->{'renewalsallowed'};
}
- if ( $renews && $renews >= $data1->{'renewals'} ) {
+ if ( $renews && $renews > $data1->{'renewals'} ) {
$renewokay = 1;
}
+ else {
+ $error="too_many";
+ }
$sth2->finish;
my ( $resfound, $resrec ) = C4::Reserves::CheckReserves($itemnumber);
if ($resfound) {
$renewokay = 0;
+ $error="on_reserve"
}
}
$sth1->finish;
- return ($renewokay);
+ return ($renewokay,$error);
}
=head2 AddRenewal
my ( $borrowernumber, $itemnumber, $branch ,$datedue ) = @_;
my $dbh = C4::Context->dbh;
-
- my $biblio = GetBiblioFromItemNumber($itemnumber);
+ my $biblio = GetBiblioFromItemNumber($itemnumber);
# If the due date wasn't specified, calculate it by adding the
# book's loan length to today's date.
unless ( $datedue ) {
(C4::Context->preference('item-level_itypes')) ? $biblio->{'itype'} : $biblio->{'itemtype'} ,
$borrower->{'branchcode'}
);
- #FIXME -- choose issuer or borrower branch.
- #FIXME -- where's the calendar ?
+ #FIXME -- choose issuer or borrower branch -- use circControl.
+
#FIXME -- $debug-ify the (0)
- my @darray = Add_Delta_DHMS( Today_and_Now(), $loanlength, 0, 0, 0 );
- $datedue = C4::Dates->new( sprintf("%04d-%02d-%02d",@darray[0..2]), 'iso');
- (0) and print STDERR "C4::Dates->new->output = " . C4::Dates->new()->output()
- . "\ndatedue->output = " . $datedue->output()
- . "\n(Y,M,D) = " . join ',', @darray;
- $datedue=CheckValidDatedue($datedue,$itemnumber,$branch);
+ #my @darray = Add_Delta_DHMS( Today_and_Now(), $loanlength, 0, 0, 0 );
+ #$datedue = C4::Dates->new( sprintf("%04d-%02d-%02d",@darray[0..2]), 'iso');
+ #(0) and print STDERR "C4::Dates->new->output = " . C4::Dates->new()->output()
+ # . "\ndatedue->output = " . $datedue->output()
+ # . "\n(Y,M,D) = " . join ',', @darray;
+ #$datedue=CheckValidDatedue($datedue,$itemnumber,$branch,$loanlength);
+ $datedue = CalcDateDue(C4::Dates->new(),$loanlength,$branch);
}
# Find the issues record for this book
my $sth =
$dbh->prepare("SELECT * FROM issues
WHERE borrowernumber=?
- AND itemnumber=?
- AND returndate IS NULL"
+ AND itemnumber=?"
);
$sth->execute( $borrowernumber, $itemnumber );
my $issuedata = $sth->fetchrow_hashref;
my $renews = $issuedata->{'renewals'} + 1;
$sth = $dbh->prepare("UPDATE issues SET date_due = ?, renewals = ?
WHERE borrowernumber=?
- AND itemnumber=?
- AND returndate IS NULL"
+ AND itemnumber=?"
);
$sth->execute( $datedue->output('iso'), $renews, $borrowernumber, $itemnumber );
$sth->finish;
# Update the renewal count on the item, and tell zebra to reindex
$renews = $biblio->{'renewals'} + 1;
- $sth = $dbh->prepare("UPDATE items SET renewals = ? WHERE itemnumber = ?");
- $sth->execute($renews,$itemnumber);
- $sth->finish();
- my $record = GetMarcItem( $biblio->{'biblionumber'}, $itemnumber );
- my $frameworkcode = GetFrameworkCode( $biblio->{'biblionumber'} );
- ModItemInMarc( $record, $biblio->{'biblionumber'}, $itemnumber, $frameworkcode );
+ ModItem({ renewals => $renews }, $biblio->{'biblionumber'}, $itemnumber);
# Charge a new rental fee, if applicable?
my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
# FIXME - I think this function could be redone to use only one SQL call.
my $sth = $dbh->prepare("select * from issues
where (borrowernumber = ?)
- and (itemnumber = ?)
- and returndate is null");
+ and (itemnumber = ?)");
$sth->execute($bornum,$itemno);
- my $data = $sth->fetchrow_hashref;
- $renewcount = $data->{'renewals'} if $data->{'renewals'};
- my $sth2 = $dbh->prepare("select renewalsallowed from items,biblioitems,itemtypes
- where (items.itemnumber = ?)
- and (items.biblioitemnumber = biblioitems.biblioitemnumber)
- and (biblioitems.itemtype = itemtypes.itemtype)");
+ my $data = $sth->fetchrow_hashref;
+ $renewcount = $data->{'renewals'} if $data->{'renewals'};
+ $sth->finish;
+ my $query = "SELECT renewalsallowed FROM items ";
+ $query .= (C4::Context->preference('item-level_itypes'))
+ ? "LEFT JOIN itemtypes ON items.itype = itemtypes.itemtype "
+ : "LEFT JOIN biblioitems on items.biblioitemnumber = biblioitems.biblioitemnumber
+ LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype ";
+ $query .= "WHERE items.itemnumber = ?";
+ my $sth2 = $dbh->prepare($query);
$sth2->execute($itemno);
- my $data2 = $sth2->fetchrow_hashref();
- $renewsallowed = $data2->{'renewalsallowed'};
- $renewsleft = $renewsallowed - $renewcount;
- warn "Renewcount:$renewcount RenewsAll:$renewsallowed RenewLeft:$renewsleft";
- return ($renewcount,$renewsallowed,$renewsleft);
+ my $data2 = $sth2->fetchrow_hashref();
+ $renewsallowed = $data2->{'renewalsallowed'};
+ $renewsleft = $renewsallowed - $renewcount;
+ return ($renewcount,$renewsallowed,$renewsleft);
}
+
=head2 GetIssuingCharges
($charge, $item_type) = &GetIssuingCharges($itemnumber, $borrowernumber);
my $borrowernumber = shift;
my $dbh = C4::Context->dbh;
my $query = "
- UPDATE issues
+ UPDATE old_issues
SET borrowernumber = NULL
WHERE returndate < '".$date."'
AND borrowernumber IS NOT NULL
$items = UpdateHoldingbranch($branch,$itmenumber);
Simple methode for updating hodlingbranch in items BDD line
+
=cut
sub UpdateHoldingbranch {
- my ( $branch,$itmenumber ) = @_;
- my $dbh = C4::Context->dbh;
-# first step validate the actual line of transfert .
- my $sth =
- $dbh->prepare(
- "update items set holdingbranch = ? where itemnumber= ?"
- );
- $sth->execute($branch,$itmenumber);
- $sth->finish;
-
-
+ my ( $branch,$itemnumber ) = @_;
+ ModItem({ holdingbranch => $branch }, undef, $itemnumber);
}
+
+=head2 CalcDateDue
+
+$newdatedue = CalcDateDue($startdate,$loanlength,$branchcode);
+this function calculates the due date given the loan length ,
+checking against the holidays calendar as per the 'useDaysMode' syspref.
+C<$startdate> = C4::Dates object representing start date of loan period (assumed to be today)
+C<$branch> = location whose calendar to use
+C<$loanlength> = loan length prior to adjustment
+=cut
+
+sub CalcDateDue {
+ my ($startdate,$loanlength,$branch) = @_;
+ if(C4::Context->preference('useDaysMode') eq 'Days') { # ignoring calendar
+ my $datedue = time + ($loanlength) * 86400;
+ #FIXME - assumes now even though we take a startdate
+ my @datearr = localtime($datedue);
+ return C4::Dates->new( sprintf("%04d-%02d-%02d", 1900 + $datearr[5], $datearr[4] + 1, $datearr[3]), 'iso');
+ } else {
+ my $calendar = C4::Calendar->new( branchcode => $branch );
+ my $datedue = $calendar->addDate($startdate, $loanlength);
+ return $datedue;
+ }
+}
+
=head2 CheckValidDatedue
+ 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.
$newdatedue = CheckValidDatedue($date_due,$itemnumber,$branchcode);
-this function return a new date due after checked if it's a repeatable or special holiday
+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> = localisation of issue
+C<$branchcode> = location of issue (affected by 'CircControl' syspref)
+C<$loanlength> = loan length prior to adjustment
=cut
-# Why not create calendar object? -
-# TODO add 'duedate' option to useDaysMode .
-sub CheckValidDatedue {
+
+sub CheckValidDatedue {
my ($date_due,$itemnumber,$branchcode)=@_;
my @datedue=split('-',$date_due->output('iso'));
my $years=$datedue[0];
# 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');
+ $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
$countrepeatable = CheckRepeatableHoliday($itemnumber,$week_day,$branchcode);
-this function check if the date due is a repeatable holiday
+this function checks if the date due is a repeatable holiday
C<$date_due> = returndate calculate with no day check
C<$itemnumber> = itemnumber
C<$branchcode> = localisation of issue
C<$day> = the day of datedue
C<$itemnumber> = itemnumber
C<$branchcode> = localisation of issue
+
=cut
+
sub CheckSpecialHolidays{
my ($years,$month,$day,$itemnumber,$branchcode) = @_;
my $dbh = C4::Context->dbh;
C<$day> = the day of datedue
C<$itemnumber> = itemnumber
C<$branchcode> = localisation of issue
+
=cut
+
sub CheckRepeatableSpecialHolidays{
my ($month,$day,$itemnumber,$branchcode) = @_;
my $dbh = C4::Context->dbh;