Small quoting fix to let fine calculation work.
[koha.git] / C4 / Circulation / Fines.pm
1 package C4::Circulation::Fines;
2
3 # $Id$
4
5 # Copyright 2000-2002 Katipo Communications
6 #
7 # This file is part of Koha.
8 #
9 # Koha is free software; you can redistribute it and/or modify it under the
10 # terms of the GNU General Public License as published by the Free Software
11 # Foundation; either version 2 of the License, or (at your option) any later
12 # version.
13 #
14 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License along with
19 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
20 # Suite 330, Boston, MA  02111-1307 USA
21
22 use strict;
23 require Exporter;
24 use DBI;
25 use C4::Context;
26 use vars qw($VERSION @ISA @EXPORT);
27
28 # set the version for version checking
29 $VERSION = 0.01;
30
31 =head1 NAME
32
33 C4::Circulation::Fines - Koha module dealing with fines
34
35 =head1 SYNOPSIS
36
37   use C4::Circulation::Fines;
38
39 =head1 DESCRIPTION
40
41 This module contains several functions for dealing with fines for
42 overdue items. It is primarily used by the 'misc/fines2.pl' script.
43
44 =head1 FUNCTIONS
45
46 =over 2
47
48 =cut
49
50 @ISA = qw(Exporter);
51 @EXPORT = qw(&Getoverdues &CalcFine &BorType &UpdateFine &ReplacementCost);
52
53 =item Getoverdues
54
55   ($count, $overdues) = &Getoverdues();
56
57 Returns the list of all overdue books.
58
59 C<$count> is the number of elements in C<@{$overdues}>.
60
61 C<$overdues> is a reference-to-array. Each element is a
62 reference-to-hash whose keys are the fields of the issues table in the
63 Koha database.
64
65 =cut
66 #'
67 sub Getoverdues{
68   my $dbh = C4::Context->dbh;
69   my $sth=$dbh->prepare("Select * from issues where date_due < now() and returndate is
70   NULL order by borrowernumber");
71   $sth->execute;
72   # FIXME - Use push @results
73   my $i=0;
74   my @results;
75   while (my $data=$sth->fetchrow_hashref){
76     $results[$i]=$data;
77     $i++;
78   }
79   $sth->finish;
80 #  print @results;
81   # FIXME - Bogus API.
82   return($i,\@results);
83 }
84
85 =item CalcFine
86
87   ($amount, $chargename, $message) =
88         &CalcFine($itemnumber, $borrowercode, $days_overdue);
89
90 Calculates the fine for a book.
91
92 The issuingrules table in the Koha database is a fine matrix, listing
93 the penalties for each type of patron for each type of item and each branch (e.g., the
94 standard fine for books might be $0.50, but $1.50 for DVDs, or staff
95 members might get a longer grace period between the first and second
96 reminders that a book is overdue).
97
98 The fine is calculated as follows: if it is time for the first
99 reminder, the fine is the value listed for the given (branch, item type,
100 borrower code) combination. If it is time for the second reminder, the
101 fine is doubled. Finally, if it is time to send the account to a
102 collection agency, the fine is set to 5 local monetary units (a really
103 good deal for the patron if the library is in Italy). Otherwise, the
104 fine is 0.
105
106 Note that the way this function is currently implemented, it only
107 returns a nonzero value on the notable days listed above. That is, if
108 the categoryitems entry says to send a first reminder 7 days after the
109 book is due, then if you call C<&CalcFine> 7 days after the book is
110 due, it will give a nonzero fine. If you call C<&CalcFine> the next
111 day, however, it will say that the fine is 0.
112
113 C<$itemnumber> is the book's item number.
114
115 C<$borrowercode> is the borrower code of the patron who currently has
116 the book.
117
118 C<$days_overdue> is the number of days elapsed since the book's due
119 date.
120
121 C<&CalcFine> returns a list of three values:
122
123 C<$amount> is the fine owed by the patron (see above).
124
125 C<$chargename> is the chargename field from the applicable record in
126 the categoryitem table, whatever that is.
127
128 C<$message> is a text message, either "First Notice", "Second Notice",
129 or "Final Notice".
130
131 =cut
132 #'
133 sub CalcFine {
134   my ($itemnumber,$bortype,$difference)=@_;
135   my $dbh = C4::Context->dbh;
136
137   # Look up the categoryitem record for this book's item type and the
138   # given borrwer type.
139   # The reason this query is so messy is that it's a messy question:
140   # given the barcode, we can find the book's items record. This gives
141   # us the biblioitems record, which gives us a set of categoryitem
142   # records. Then we select the one that corresponds to the desired
143   # borrower type.
144
145   # FIXME - Is it really necessary to get absolutely everything from
146   # all four tables? It looks as if this code only wants
147   # firstremind, chargeperiod, accountsent, and chargename from the
148   # categoryitem table.
149
150   my $sth=$dbh->prepare("Select * from items,biblioitems,itemtypes,categoryitem where items.itemnumber=?
151   and items.biblioitemnumber=biblioitems.biblioitemnumber and
152   biblioitems.itemtype=itemtypes.itemtype and
153   categoryitem.itemtype=itemtypes.itemtype and
154   categoryitem.categorycode=? and
155   (items.itemlost <> 1 or items.itemlost is NULL)");
156 #  print $query;
157   $sth->execute($itemnumber,$bortype);
158   my $data=$sth->fetchrow_hashref;
159         # FIXME - Error-checking: the item might be lost, or there
160         # might not be an entry in 'categoryitem' for this item type
161         # or borrower type.
162   $sth->finish;
163   my $amount=0;
164   my $printout;
165
166   # Is it time to send out the first reminder?
167   # FIXME - I'm not sure the "=="s are correct here. Let's say that
168   # $data->{firstremind} is today, but 'fines2.pl' doesn't run for
169   # some reason (the cron daemon died, the server crashed, the
170   # sysadmin had the machine down for maintenance, or whatever).
171   #
172   # Then the next day, the book is $data->{firstremind}+1 days
173   # overdue. But this function returns $amount == 0, $printout ==
174   # undef, on the assumption that 'fines2.pl' ran the previous day. So
175   # the first thing the patron gets is a second notice, but that's a
176   # week after the server crash, so people may not connect the two
177   # events.
178   if ($difference == $data->{'firstremind'}){
179     # Yes. Set the fine as listed.
180     $amount=$data->{'fine'};
181     $printout="First Notice";
182   }
183
184   # Is it time to send out a second reminder?
185   my $second=$data->{'firstremind'}+$data->{'chargeperiod'};
186   if ($difference == $second){
187     # Yes. The fine is double.
188     $amount=$data->{'fine'}*2;
189     $printout="Second Notice";
190   }
191
192   # Is it time to send the account to a collection agency?
193   # FIXME - At least, I *think* that's what this code is doing.
194   if ($difference == $data->{'accountsent'} && $data->{'fine'} > 0){
195     # Yes. Set the fine at 5 local monetary units.
196     # FIXME - This '5' shouldn't be hard-wired.
197     $amount=5;
198     $printout="Final Notice";
199   }
200   return($amount,$data->{'chargename'},$printout);
201 }
202
203 =item UpdateFine
204
205   &UpdateFine($itemnumber, $borrowernumber, $amount, $type, $description);
206
207 (Note: the following is mostly conjecture and guesswork.)
208
209 Updates the fine owed on an overdue book.
210
211 C<$itemnumber> is the book's item number.
212
213 C<$borrowernumber> is the borrower number of the patron who currently
214 has the book on loan.
215
216 C<$amount> is the current amount owed by the patron.
217
218 C<$type> will be used in the description of the fine.
219
220 C<$description> is a string that must be present in the description of
221 the fine. I think this is expected to be a date in DD/MM/YYYY format.
222
223 C<&UpdateFine> looks up the amount currently owed on the given item
224 and sets it to C<$amount>, creating, if necessary, a new entry in the
225 accountlines table of the Koha database.
226
227 =cut
228 #'
229 # FIXME - This API doesn't look right: why should the caller have to
230 # specify both the item number and the borrower number? A book can't
231 # be on loan to two different people, so the item number should be
232 # sufficient.
233 sub UpdateFine {
234   my ($itemnum,$bornum,$amount,$type,$due)=@_;
235   my $dbh = C4::Context->dbh;
236   # FIXME - What exactly is this query supposed to do? It looks up an
237   # entry in accountlines that matches the given item and borrower
238   # numbers, where the description contains $due, and where the
239   # account type has one of several values, but what does this _mean_?
240   # Does it look up existing fines for this item?
241   # FIXME - What are these various account types? ("FU", "O", "F", "M")
242   my $sth=$dbh->prepare("Select * from accountlines where itemnumber=? and
243   borrowernumber=? and (accounttype='FU' or accounttype='O' or
244   accounttype='F' or accounttype='M') and description like ?");
245   $sth->execute($itemnum,$bornum,"%$due%");
246
247   if (my $data=$sth->fetchrow_hashref){
248     # I think this if-clause deals with the case where we're updating
249     # an existing fine.
250 #    print "in accounts ...";
251     if ($data->{'amount'} != $amount){
252
253 #      print "updating";
254       my $diff=$amount - $data->{'amount'};
255       my $out=$data->{'amountoutstanding'}+$diff;
256       my $sth2=$dbh->prepare("update accountlines set date=now(), amount=?,
257       amountoutstanding=?,accounttype='FU' where
258       borrowernumber=? and itemnumber=?
259       and (accounttype='FU' or accounttype='O') and description like ?");
260       $sth2->execute($amount,$out,$data->{'borrowernumber'},$data->{'itemnumber'},"%$due%");
261       $sth2->finish;
262     } else {
263 #      print "no update needed $data->{'amount'}"
264     }
265   } else {
266     # I think this else-clause deals with the case where we're adding
267     # a new fine.
268     my $sth4=$dbh->prepare("select title from biblio,items where items.itemnumber=?
269     and biblio.biblionumber=items.biblionumber");
270     $sth4->execute($itemnum);
271     my $title=$sth4->fetchrow_hashref;
272     $sth4->finish;
273  #   print "not in account";
274     my $sth3=$dbh->prepare("Select max(accountno) from accountlines");
275     $sth3->execute;
276     # FIXME - Make $accountno a scalar.
277     my @accountno=$sth3->fetchrow_array;
278     $sth3->finish;
279     $accountno[0]++;
280     my $sth2=$dbh->prepare("Insert into accountlines
281     (borrowernumber,itemnumber,date,amount,
282     description,accounttype,amountoutstanding,accountno) values
283     (?,?,now(),?,?,'FU',?,?)");
284     $sth2->execute($bornum,$itemnum,$amount,"$type $title->{'title'} $due",$amount,$accountno[0]);
285     $sth2->finish;
286   }
287   $sth->finish;
288 }
289
290 =item BorType
291
292   $borrower = &BorType($borrowernumber);
293
294 Looks up a patron by borrower number.
295
296 C<$borrower> is a reference-to-hash whose keys are all of the fields
297 from the borrowers and categories tables of the Koha database. Thus,
298 C<$borrower> contains all information about both the borrower and
299 category he or she belongs to.
300
301 =cut
302 #'
303 sub BorType {
304   my ($borrowernumber)=@_;
305   my $dbh = C4::Context->dbh;
306   my $sth=$dbh->prepare("Select * from borrowers,categories where
307   borrowernumber=? and
308 borrowers.categorycode=categories.categorycode");
309   $sth->execute($borrowernumber);
310   my $data=$sth->fetchrow_hashref;
311   $sth->finish;
312   return($data);
313 }
314
315 =item ReplacementCost
316
317   $cost = &ReplacementCost($itemnumber);
318
319 Returns the replacement cost of the item with the given item number.
320
321 =cut
322 #'
323 sub ReplacementCost{
324   my ($itemnum)=@_;
325   my $dbh = C4::Context->dbh;
326   my $sth=$dbh->prepare("Select replacementprice from items where itemnumber=?");
327   $sth->execute($itemnum);
328   # FIXME - Use fetchrow_array or something.
329   my $data=$sth->fetchrow_hashref;
330   $sth->finish;
331   return($data->{'replacementprice'});
332 }
333
334 1;
335 __END__
336
337 =back
338
339 =head1 AUTHOR
340
341 Koha Developement team <info@koha.org>
342
343 =cut