From 882c710e06724b4bf9cb11d0b994d3a47c267fda Mon Sep 17 00:00:00 2001 From: Chris Cormack Date: Tue, 31 May 2011 13:44:06 +1200 Subject: [PATCH] Bug 6431 : New modules for doing hourly circulation These live now in the Koha:: namespace and reference no modules in C4 They are written in OO style, more pod and tests to follow --- Koha/Circulation.pm | 80 ++++++++++++++ Koha/Circulation/Issue.pm | 251 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 331 insertions(+), 0 deletions(-) create mode 100644 Koha/Circulation.pm create mode 100644 Koha/Circulation/Issue.pm diff --git a/Koha/Circulation.pm b/Koha/Circulation.pm new file mode 100644 index 0000000..e3bd1c4 --- /dev/null +++ b/Koha/Circulation.pm @@ -0,0 +1,80 @@ +package Koha::Circulation; + +# Copyright 2011 Catalyst IT +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use 5.010001; +use strict; +use warnings; + +use base qw(Class::Accessor); + +__PACKAGE__->follow_best_practice; +__PACKAGE__->mk_accessors(qw( borrowernumber itemnumber borrower context)); + +=head1 NAME + +Koha::Circulation + +=cut + +=head2 check_valid_barcode + $exists = $circulation->check_valid_barcode( $barcode ); + +Checks if the barcode exists in the database + +=cut + +sub check_valid_barcode { + my $self = shift; + my $barcode = shift; + my $context = $self->get_context; + my $query = "SELECT count(barcode) FROM items WHERE barcode = ?"; + my $sth = $context->dbh->prepare($query); + $sth->execute($barcode); + my $exists = $sth->fetchrow; + $sth->finish; + return $exists +} + +=head2 checked_out + + $checked_out = $circulation->checked_out($itemnumber); + +Returns the row of the issues table if the item is currently checked out + +C<$itemnumber> is the itemnumber. + +C<$checked_out> is a hashref of the row from the issues table. + +=cut + +sub checked_out { + my $self = shift; + my $itemnumber = shift; + return unless $itemnumber; + my $context = $self->get_context; + my $sth = $context->dbh->prepare("SELECT * FROM issues WHERE issues.itemnumber = ?"); + $sth->execute($itemnumber); + my $data = $sth->fetchrow_hashref; + return $data; +} + + +1; +__END__ + diff --git a/Koha/Circulation/Issue.pm b/Koha/Circulation/Issue.pm new file mode 100644 index 0000000..292c7aa --- /dev/null +++ b/Koha/Circulation/Issue.pm @@ -0,0 +1,251 @@ +package Koha::Circulation::Issue; + +# Copyright 2011 Catalyst IT +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use 5.010001; +use strict; +use warnings; + +use base 'Koha::Circulation'; + +use Koha::Dates; +use Koha::Calendar; + +sub checkout { + my $self = shift; + my ($item,$issuedate,$branch,$datedue) = @_; + my $context = $self->get_context; + my $borrower = $self->get_borrower; + my $checked_out = $self->checked_out($item->{'itemnumber'}); + if ($checked_out) { + # Item is on loan + if ($checked_out->{'borrowernumber'} == $borrower->{'borrowernumber'}){ + # Item is on loan to the current borrower so we attempt a renewal + $self->renew($item,$branch,$datedue,$issuedate); + } + else { + # on loan to another, so we must return it first + $self->checkin($item); + } + } + my $sth = $context->dbh->prepare("INSERT INTO issues + (borrowernumber, itemnumber,issuedate, date_due, branchcode) + VALUES (?,?,?,?,?)"); + $sth->execute( + $borrower->{'borrowernumber'}, # borrowernumber + $item->{'itemnumber'}, # itemnumber + $issuedate->output('iso'), # issuedate + $datedue->output('iso'), # date_due + C4::Context->userenv->{'branch'} # branchcode + ); + +} + +sub checkin { + my $self = shift; + my $item = shift; + my $context = $self->get_context; + my $branch = $context->userenv->{'branch'}; + + + +} + +=head2 calc_date_due + +$newdatedue = $issue->calc_date_due($startdate,$itemtype,$branchcode); + +this function calculates the due date given the start date and configured circulation rules, +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<$itemtype> = itemtype code of item in question +C<$branch> = location whose calendar to use + +=cut + +sub calc_date_due { + my $self = shift; + my ($startdate,$itemtype,$branch) = @_; + my $datedue; + my $loanlength = $self->get_loan_length($itemtype,$branch); + my $context = $self->get_context; + my $borrower = $self->get_borrower; + + # if globalDueDate ON the datedue is set to that date + # FIXME we can't use C4::Dates here + if ($context->preference('globalDueDate') && $context->preference('globalDueDate') =~ C4::Dates->regexp('syspref') ){ + $datedue = Koha::Dates->new( $context->preference('globalDueDate') ); + } + else { + # calculate date normally + if ($context->preference('useDaysMode') eq 'Days') { # ignoring calendar + my $timedue = time + ($loanlength) * 60; #Loanlength is stored as minutes + #FIXME also ignores startdate + my @datearr = localtime($timedue); + $datedue = Koha::Dates->new( sprintf("%04d-%02d-%02d %02d:%02d:%02d", 1900 + $datearr[5], $datearr[4] + 1, $datearr[3], $datearr[2], $datearr[1], $datearr[0]), 'iso'); + } + else { + my $calendar = Koha::Calendar->new( branchcode => $branch, context => $self->get_context ); + $datedue = $calendar->addDate($startdate, $loanlength * 60); # loanlength is expresed in minutes in the db + } + } + my ($hardduedate, $hardduedatecompare) = $self->get_hard_due_date($itemtype,$branch); + if ($hardduedate && $hardduedate->output('iso') && $hardduedate->output('iso') !~ /^0000\-00\-00/){ + # if the calculated due date is after the 'before' Hard Due Date (ceiling), override + if ( $datedue->output( 'iso' ) gt $hardduedate->output( 'iso' ) && $hardduedatecompare == -1) { + $datedue = $hardduedate; + } + elsif ($datedue->output('iso') lt $hardduedate->output( 'iso' ) && $hardduedatecompare == 1) { + $datedue = $hardduedate; + } + elsif ( $hardduedatecompare == 0) { + $datedue = $hardduedate; + } + } + if ($context->preference('ReturnBeforeExpiry') && $datedue->output('iso') gt $borrower->{dateexpiry} ) { + $datedue = Koha::Dates->new( $borrower->{dateexpiry}, 'iso' ); + } + return $datedue; +} + +=head2 get_hard_due_date + + my ($hardduedate,$hardduedatecompare) = $issue->get_hard_due_date($itemtype,branchcode) + +Get the Hard Due Date and it's comparison for an itemtype, a borrower type and a branch + +=cut + +sub get_hard_due_date { + my $self = shift; + my ( $itemtype, $branchcode ) = @_; + my $context = $self->get_context; + my $borrower = $self->get_borrower; + my $sth = + $context->dbh->prepare( +"SELECT hardduedate, hardduedatecompare + FROM issuingrules WHERE categorycode=? AND itemtype=? AND branchcode=?" + ); + $sth->execute( $borrower->{'categorycode'}, $itemtype, $branchcode ); + my $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + $sth->execute( $borrower->{'categorycode'}, "*", $branchcode ); + $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + $sth->execute( "*", $itemtype, $branchcode ); + $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + $sth->execute( "*", "*", $branchcode ); + $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + $sth->execute( $borrower->{'categorycode'}, $itemtype, "*" ); + $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + $sth->execute( $borrower->{'categorycode'}, "*", "*" ); + $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + $sth->execute( "*", $itemtype, "*" ); + $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + $sth->execute( "*", "*", "*" ); + $results = $sth->fetchrow_hashref; + return (Koha::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare}) + if defined($results) && $results->{hardduedate} ne 'NULL'; + + # if no rule is set => return undefined + return (undef, undef); +} + +=head2 get_loan_length + + my $loanlength = $issue->get_loan_length($itemtype,branchcode) + +Get loan length for an itemtype, a borrower type and a branch + +=cut + +sub get_loan_length { + my $self = shift; + my ($itemtype,$branchcode) = @_; + my $context = $self->get_context; + my $borrower = $self->get_borrower; + my $sth = $context->dbh->prepare("SELECT issuelength FROM issuingrules WHERE categorycode=? + AND itemtype=? AND branchcode=? AND issuelength IS NOT NULL"); + $sth->execute( $borrower->{'categorycode'}, $itemtype, $branchcode ); + + my $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + $sth->execute( $borrower->{'categorycode'}, "*", $branchcode ); + $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + $sth->execute( "*", $itemtype, $branchcode ); + $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + $sth->execute( "*", "*", $branchcode ); + $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + $sth->execute( $borrower->{'categorycode'}, $itemtype, "*" ); + $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + $sth->execute( $borrower->{'categorycode'}, "*", "*" ); + $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + $sth->execute( "*", $itemtype, "*" ); + $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + $sth->execute( "*", "*", "*" ); + $loanlength = $sth->fetchrow_hashref; + return $loanlength->{issuelength} + if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; + + # if no rule is set => 21 days (hardcoded) + return 21; +} + + +1; +__END__ + -- 1.7.4.1