koha-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Koha-cvs] koha/C4/Circulation Fines.pm [dev_week]


From: Kyle Hall
Subject: [Koha-cvs] koha/C4/Circulation Fines.pm [dev_week]
Date: Tue, 01 Apr 2008 15:18:22 +0000

CVSROOT:        /sources/koha
Module name:    koha
Branch:         dev_week
Changes by:     Kyle Hall <kylemhall>   08/04/01 15:18:22

Modified files:
        C4/Circulation : Fines.pm 

Log message:
        Added a number of useful fines functions, including a 'corrent' 
function for getting issuing rules, which takes into account wildcards.
        Also added CreateFineOnReturn as an alternative to the nightly fines 
generator.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/koha/C4/Circulation/Fines.pm?cvsroot=koha&only_with_tag=dev_week&r1=1.9.2.2.2.1&r2=1.9.2.2.2.2

Patches:
Index: Fines.pm
===================================================================
RCS file: /sources/koha/koha/C4/Circulation/Fines.pm,v
retrieving revision 1.9.2.2.2.1
retrieving revision 1.9.2.2.2.2
diff -u -b -r1.9.2.2.2.1 -r1.9.2.2.2.2
--- Fines.pm    3 Aug 2006 05:25:41 -0000       1.9.2.2.2.1
+++ Fines.pm    1 Apr 2008 15:18:21 -0000       1.9.2.2.2.2
@@ -1,6 +1,6 @@
 package C4::Circulation::Fines;
 
-# $Id: Fines.pm,v 1.9.2.2.2.1 2006/08/03 05:25:41 kados Exp $
+# $Id: Fines.pm,v 1.9.2.2.2.2 2008/04/01 15:18:21 kylemhall Exp $
 
 # Copyright 2000-2002 Katipo Communications
 #
@@ -22,6 +22,11 @@
 use strict;
 require Exporter;
 use DBI;
+use POSIX;
+use Date::Calc qw(
+Add_Delta_Days
+);
+
 use C4::Context;
 use vars qw($VERSION @ISA @EXPORT);
 
@@ -48,7 +53,7 @@
 =cut
 
 @ISA = qw(Exporter);
address@hidden = qw(&Getoverdues &CalcFine &BorType &UpdateFine 
&ReplacementCost);
address@hidden = qw(&Getoverdues &CalcFine &BorType &UpdateFine 
&ReplacementCost &CreateFineOnReturn &CalculateFine);
 
 =item Getoverdues
 
@@ -348,6 +353,217 @@
   return($data->{'replacementprice'});
 }
 
+
+## Function Calculate Fine
+## A New Fine Calculator
+## $future_date is an optional date ( YYYY-MM-DD ) for estimating a fine in 
the future.
+## Returns amount of fine.
+sub CalculateFine {
+  my $maxFine = 10;
+  
+  my ( $itembarcode, $itemnumber, $future_date ) = @_;
+
+warn "CalculateFine( $itembarcode, $itemnumber, $future_date )";
+  
+  my $return_date = sprintf("%04d-%02d-%02d", (localtime(time))[5] + 1900, 
(localtime(time))[4] + 1, (localtime(time))[3]);
+  if ( $future_date ) {
+    $return_date = $future_date;
+  }
+  
+warn "CalculateFine: Return Date: $return_date";
+
+  my $dbh = C4::Context->dbh;
+
+  my $fineData = _GetFineData( $itembarcode, $itemnumber, $future_date );  
+
+warn "CalculateFine: Borrowernumber: " . $fineData->{'borrowernumber'};
+warn "CalculateFine: Date of Issue: " . $fineData->{'issue_date'};
+warn "CalculateFine: Date Due: " . $fineData->{'date_due'};
+warn "CalculateFine: Days Overdue: " . $fineData->{'days_overdue'};
+
+  if ( $fineData->{'days_overdue'} < 1 ) { return 0; } ## Short circuit for 
speed
+
+  my $issuing_rule = _GetIssuingRule( $fineData->{'categorycode'}, 
$fineData->{'itemtype'}, $fineData->{'holdingbranch'} );  
+
+  ## We don't charge for grace days ( i.e. firstremind ) so we need to skip 
them for the number of holidays calculation
+  my ( $iYear, $iMonth, $iDay ) = split( /-/, $fineData->{'date_due'} );
+  ( $iYear, $iMonth, $iDay ) = Add_Delta_Days( $iYear, $iMonth, $iDay, 
$issuing_rule->{'firstremind'} );
+  my $start_charging_date = "$iYear-$iMonth-$iDay";
+
+warn "CalculateFine: Date to Start Charging: $start_charging_date";
+warn "CalculateFine: First Remind: " . $issuing_rule->{'firstremind'};
+warn "CalculateFine: Holidays: " . _GetHolidaysBetween( $start_charging_date, 
$return_date, $fineData->{'holdingbranch'} );
+
+  my $days_to_charge = $fineData->{'days_overdue'} - 
$issuing_rule->{'firstremind'} - _GetHolidaysBetween( $start_charging_date, 
$return_date, $fineData->{'holdingbranch'} );
+
+warn "CalculateFine: Days to Charge: $days_to_charge";
+  
+  if ( $days_to_charge < 1 ) { return 0; } ## Short circuit for speed
+  
+  my $fine = $days_to_charge * $issuing_rule->{'fine'} / 
$issuing_rule->{'chargeperiod'};
+
+  if ( $fine > $maxFine ) { $fine = $maxFine; }
+  
+warn "CalculateFine: Fine: $fine";
+  
+  return $fine;
+}
+
+## Function CreateFine
+## This function accepts to arguments, $itembarcode and $itemnumber
+## Only one is required, if both are passed $itemnumber will be used.
+## NOTE: This function should be run right before an item is returned or 
renewed.
+sub CreateFineOnReturn {
+  my ( $itembarcode, $itemnumber ) = @_;
+
+  warn "CreateFineOnReturn( $itembarcode, $itemnumber )";
+  
+  my $dbh = C4::Context->dbh;
+  
+  my $amount = CalculateFine( $itembarcode, $itemnumber );
+
+  warn "CreateFineOnReturn: Amount: $amount";
+
+  if ( $amount > 0 ) {
+     my $fineData = _GetFineData( $itembarcode, $itemnumber );
+     my $description = $fineData->{'title'} . " ( " . $fineData->{'barcode'} . 
" ) on " . $fineData->{'date_due'};
+     UpdateFine( $fineData->{'itemnumber'}, $fineData->{'borrowernumber'}, 
$amount, my $type = 'F', $description );
+  }
+}
+
+## Function getFineData
+## This function returns an array associated array of data about the borrower 
and the item
+## $future_date is an optional date ( YYYY-MM-DD ) for estimating a fine in 
the future.
+sub _GetFineData {
+  my ( $itembarcode, $itemnumber, $future_date ) = @_;
+  
+  my $diff_date = "NOW()";
+  if ( $future_date ) {
+    $diff_date = "DATE( $future_date )";
+  }
+  
+  my $dbh = C4::Context->dbh;
+  
+  my $sql = "SELECT items.itemnumber, 
+                    items.itemcallnumber, 
+                    issues.date_due,
+                    issues.issue_date,
+                    DATEDIFF( $diff_date, issues.date_due ) as days_overdue, 
+                    borrowers.borrowernumber, 
+                    borrowers.categorycode, 
+                    biblioitems.itemtype, 
+                    items.price, 
+                    items.barcode, 
+                    items.holdingbranch, 
+                    biblio.title
+          FROM items, issues, borrowers, biblio, biblioitems
+          WHERE
+          issues.itemnumber = items.itemnumber
+          AND borrowers.borrowernumber = issues.borrowernumber
+          AND items.biblionumber = biblioitems.biblionumber
+          AND items.biblionumber = biblio.biblionumber
+          AND issues.returndate IS NULL
+           ";
+
+  if ( $itembarcode ) {
+    $sql .= "AND items.barcode = ?";
+  } else {
+    $sql .= "AND items.itemnumber = ?";
+  }
+  
+  my $sth = $dbh->prepare( $sql );
+  
+  if ( $itembarcode ) {
+    $sth->execute( $itembarcode );
+  } else {
+    $sth->execute( $itemnumber );
+  }
+  
+  my $fineData = $sth->fetchrow_hashref();
+
+  return $fineData;
+}
+
+## _GetIssuingRule takes the borrower categorycode, itemtype, and the item's 
holdingbranch
+## And returns the proper issuing rule, if there is no exact issuing rule for 
the combination,
+## it tries to match just the category code, if that fails it tries just the 
itemtype
+## if that fails, it returns the default rule for the branch
+sub _GetIssuingRule {
+  my ( $categorycode, $itemtype, $holdingbranch ) = @_;
+  
+  my $issuingrule = _CheckForIssuingRule( $categorycode, $itemtype, 
$holdingbranch );
+  if ( $issuingrule ) { return $issuingrule; }
+  
+  my $issuingrule = _CheckForIssuingRule( $categorycode, '', $holdingbranch );
+  if ( $issuingrule ) { return $issuingrule; }
+
+  my $issuingrule = _CheckForIssuingRule( '', $itemtype, $holdingbranch );
+  if ( $issuingrule ) { return $issuingrule; }
+
+  my $issuingrule = _CheckForIssuingRule( '', '', $holdingbranch );
+  return $issuingrule;
+  
+}
+
+## Checks to see if there is an issuing rule for the given criteria
+## $categorycode and/or $itemtype can be empty to indicate wildcard
+## $holdingbranch is the current holdingbranch for the item
+## If the issuingrule exists, it returns a hashref for it, if not, it returns 0
+sub _CheckForIssuingRule {
+  my ( $categorycode, $itemtype, $holdingbranch ) = @_;
+ 
+  if ( ! $categorycode ) { $categorycode = "*"; }
+  if ( ! $itemtype ) { $itemtype = "*"; }
+
+  my $dbh = C4::Context->dbh;
+  
+  my $sql = "SELECT * FROM issuingrules WHERE categorycode LIKE ? AND itemtype 
LIKE ? AND branchcode LIKE ?";
+
+  my $sth = $dbh->prepare( $sql );
+  
+  $sth->execute( $categorycode, $itemtype, $holdingbranch );
+  
+  my $issuingrule = $sth->fetchrow_hashref();
+  
+  return $issuingrule;
+}
+
+## Takes a starting and ending date
+## in the format YYYY-MM-DD
+## and returns the number of 
+## holidays between the two dates
+sub _GetHolidaysBetween {
+  my ( $startDate, $endDate, $branchcode ) = @_;
+  
+  my ( $sYear, $sMonth, $sDay ) = split( /-/, $startDate );
+  my ( $eYear, $eMonth, $eDay ) = split( /-/, $endDate );
+
+  my $holidaysCount = 0;
+  
+  my $calendar = C4::Calendar->new( branchcode => $branchcode );
+  
+  $holidaysCount += $calendar->isHoliday( $sDay, $sMonth, $sYear );
+  
+  while ( mktime( 0, 0, 0, $sDay, $sMonth - 1, $sYear - 1900, 0, 0 ) <= 
mktime( 0, 0, 0, $eDay, $eMonth - 1, $eYear - 1900, 0, 0 ) ) {
+    ( $sYear, $sMonth, $sDay ) = Add_Delta_Days( $sYear, $sMonth, $sDay, 1 );
+    $holidaysCount += $calendar->isHoliday( $sDay, $sMonth, $sYear );
+  }
+  
+  return $holidaysCount;
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Koha Developement team <address@hidden>
+
+=cut
+
+
 1;
 __END__
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]