Code Cleaning Members.
[koha.git] / C4 / Accounts.pm
1 package C4::Accounts;
2
3 # Copyright 2000-2002 Katipo Communications
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20 # $Id$
21
22 use strict;
23 require Exporter;
24 use C4::Context;
25 use C4::Stats;
26 use C4::Members;
27 #use C4::Circulation;
28 use vars qw($VERSION @ISA @EXPORT);
29
30 # set the version for version checking
31 $VERSION = do { my @v = '$Revision$' =~ /\d+/g; 
32 shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
33
34 =head1 NAME
35
36 C4::Accounts - Functions for dealing with Koha accounts
37
38 =head1 SYNOPSIS
39
40 use C4::Accounts;
41
42 =head1 DESCRIPTION
43
44 The functions in this module deal with the monetary aspect of Koha,
45 including looking up and modifying the amount of money owed by a
46 patron.
47
48 =head1 FUNCTIONS
49
50 =cut
51
52 @ISA = qw(Exporter);
53 @EXPORT = qw(&recordpayment &fixaccounts &makepayment &manualinvoice
54 &getnextacctno &reconcileaccount);
55
56
57 =head2 recordpayment
58
59   &recordpayment($borrowernumber, $payment);
60
61 Record payment by a patron. C<$borrowernumber> is the patron's
62 borrower number. C<$payment> is a floating-point number, giving the
63 amount that was paid. 
64
65 Amounts owed are paid off oldest first. That is, if the patron has a
66 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
67 of $1.50, then the oldest fine will be paid off in full, and $0.50
68 will be credited to the next one.
69
70 =cut
71
72 #'
73 sub recordpayment{
74   #here we update both the accountoffsets and the account lines
75   my ($borrowernumber,$data)=@_;
76   my $dbh = C4::Context->dbh;
77   my $newamtos = 0;
78   my $accdata = "";
79   my $branch=C4::Context->userenv->{'branch'};
80   my $amountleft = $data;
81   # begin transaction
82   my $nextaccntno = getnextacctno($borrowernumber);
83   # get lines with outstanding amounts to offset
84   my $sth = $dbh->prepare("select * from accountlines
85   where (borrowernumber = ?) and (amountoutstanding<>0)
86   order by date");
87   $sth->execute($borrowernumber);
88   # offset transactions
89   while (($accdata=$sth->fetchrow_hashref) and ($amountleft>0)){
90      if ($accdata->{'amountoutstanding'} < $amountleft) {
91         $newamtos = 0;
92         $amountleft -= $accdata->{'amountoutstanding'};
93      }  else {
94         $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
95         $amountleft = 0;
96      }
97      my $thisacct = $accdata->{accountno};
98      my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
99      where (borrowernumber = ?) and (accountno=?)");
100      $usth->execute($newamtos,$borrowernumber,$thisacct);
101      $usth->finish;
102      $usth = $dbh->prepare("insert into accountoffsets
103      (borrowernumber, accountno, offsetaccount,  offsetamount)
104      values (?,?,?,?)");
105      $usth->execute($borrowernumber,$accdata->{'accountno'},$nextaccntno,$newamtos);
106      $usth->finish;
107   }
108   # create new line
109   my $usth = $dbh->prepare("insert into accountlines
110   (borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding)
111   values (?,?,now(),?,'Payment,thanks','Pay',?)");
112   $usth->execute($borrowernumber,$nextaccntno,0-$data,0-$amountleft);
113   $usth->finish;
114   UpdateStats($branch,'payment',$data,'','','',$borrowernumber);
115   $sth->finish;
116 }
117
118 =head2 makepayment
119
120   &makepayment($borrowernumber, $acctnumber, $amount, $branchcode);
121
122 Records the fact that a patron has paid off the entire amount he or
123 she owes.
124
125 C<$borrowernumber> is the patron's borrower number. C<$acctnumber> is
126 the account that was credited. C<$amount> is the amount paid (this is
127 only used to record the payment. It is assumed to be equal to the
128 amount owed). C<$branchcode> is the code of the branch where payment
129 was made.
130
131 =cut
132
133 #'
134 # FIXME - I'm not at all sure about the above, because I don't
135 # understand what the acct* tables in the Koha database are for.
136 sub makepayment{
137   #here we update both the accountoffsets and the account lines
138   #updated to check, if they are paying off a lost item, we return the item
139   # from their card, and put a note on the item record
140   my ($borrowernumber,$accountno,$amount,$user,$branch)=@_;
141   my $dbh = C4::Context->dbh;
142   # begin transaction
143   my $nextaccntno = getnextacctno($borrowernumber);
144   my $newamtos=0;
145   my $sth=$dbh->prepare("Select * from accountlines where  borrowernumber=? and accountno=?");
146   $sth->execute($borrowernumber,$accountno);
147   my $data=$sth->fetchrow_hashref;
148   $sth->finish;
149
150   $dbh->do(<<EOT);
151         UPDATE  accountlines
152         SET     amountoutstanding = 0
153         WHERE   borrowernumber = $borrowernumber
154           AND   accountno = $accountno
155 EOT
156
157 #  print $updquery;
158   $dbh->do(<<EOT);
159         INSERT INTO     accountoffsets
160                         (borrowernumber, accountno, offsetaccount,
161                          offsetamount)
162         VALUES          ($borrowernumber, $accountno, $nextaccntno, $newamtos)
163 EOT
164
165   # create new line
166   my $payment=0-$amount;
167   $dbh->do(<<EOT);
168         INSERT INTO     accountlines
169                         (borrowernumber, accountno, date, amount,
170                          description, accounttype, amountoutstanding)
171         VALUES          ($borrowernumber, $nextaccntno, now(), $payment,
172                         'Payment,thanks - $user', 'Pay', 0)
173 EOT
174
175   # FIXME - The second argument to &UpdateStats is supposed to be the
176   # branch code.
177   # UpdateStats is now being passed $accountno too. MTJ
178   UpdateStats($user,'payment',$amount,'','','',$borrowernumber,$accountno);
179   $sth->finish;
180   #check to see what accounttype
181   if ($data->{'accounttype'} eq 'Rep' || $data->{'accounttype'} eq 'L'){
182     returnlost($borrowernumber,$data->{'itemnumber'});
183   }
184 }
185
186 =head2 getnextacctno
187
188   $nextacct = &getnextacctno($borrowernumber);
189
190 Returns the next unused account number for the patron with the given
191 borrower number.
192
193 C<$dbh> is a DBI::db handle to the Koha database.
194
195 =cut
196
197 #'
198 # FIXME - Okay, so what does the above actually _mean_?
199 sub getnextacctno {
200   my ($borrowernumber)=@_;
201   my $nextaccntno = 1;
202   my $dbh = C4::Context->dbh;
203   my $sth = $dbh->prepare("SELECT * FROM accountlines
204   WHERE (borrowernumber = ?)
205   ORDER BY accountno DESC");
206   $sth->execute($borrowernumber);
207   if (my $accdata=$sth->fetchrow_hashref){
208     $nextaccntno = $accdata->{'accountno'} + 1;
209   }
210   $sth->finish;
211   return($nextaccntno);
212 }
213
214 =head2 fixaccounts
215
216   &fixaccounts($borrowernumber, $accountnumber, $amount);
217
218 =cut
219
220 #'
221 # FIXME - I don't understand what this function does.
222 sub fixaccounts {
223   my ($borrowernumber,$accountno,$amount)=@_;
224   my $dbh = C4::Context->dbh;
225   my $sth=$dbh->prepare("Select * from accountlines where borrowernumber=?
226      and accountno=?");
227   $sth->execute($borrowernumber,$accountno);
228   my $data=$sth->fetchrow_hashref;
229         # FIXME - Error-checking
230   my $diff=$amount-$data->{'amount'};
231   my $outstanding=$data->{'amountoutstanding'}+$diff;
232   $sth->finish;
233
234   $dbh->do(<<EOT);
235         UPDATE  accountlines
236         SET     amount = '$amount',
237                 amountoutstanding = '$outstanding'
238         WHERE   borrowernumber = $borrowernumber
239           AND   accountno = $accountno
240 EOT
241  }
242
243 # FIXME - Never used, but not exported, either.
244 sub returnlost{
245   my ($borrowernumber,$itemnum)=@_;
246   my $dbh = C4::Context->dbh;
247   my $borrower=GetMember($borrowernumber,'borrowernumber');
248   my $sth=$dbh->prepare("Update issues set returndate=now() where
249   borrowernumber=? and itemnumber=? and returndate is null");
250   $sth->execute($borrowernumber,$itemnum);
251   $sth->finish;
252   my @datearr = localtime(time);
253   my $date = (1900+$datearr[5])."-".($datearr[4]+1)."-".$datearr[3];
254   my $bor="$borrower->{'firstname'} $borrower->{'surname'} $borrower->{'cardnumber'}";
255   $sth=$dbh->prepare("Update items set paidfor=? where itemnumber=?");
256   $sth->execute("Paid for by $bor $date",$itemnum);
257   $sth->finish;
258 }
259
260 =head2 manualinvoice
261
262   &manualinvoice($borrowernumber, $itemnumber, $description, $type,
263                  $amount, $user);
264
265 C<$borrowernumber> is the patron's borrower number.
266 C<$description> is a description of the transaction.
267 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
268 or C<REF>.
269 C<$itemnumber> is the item involved, if pertinent; otherwise, it
270 should be the empty string.
271
272 =cut
273
274 #'
275 # FIXME - Okay, so what does this function do, really?
276 sub manualinvoice{
277   my ($borrowernumber,$itemnum,$desc,$type,$amount,$user)=@_;
278   my $dbh = C4::Context->dbh;
279   my $notifyid;
280   my $insert;
281   $itemnum=~ s/ //g;
282   my $accountno=getnextacctno($borrowernumber);
283   my $amountleft=$amount;
284
285   if ($type eq 'CS' || $type eq 'CB' || $type eq 'CW'
286   || $type eq 'CF' || $type eq 'CL'){
287     my $amount2=$amount*-1;     # FIXME - $amount2 = -$amount
288     $amountleft=fixcredit($borrowernumber,$amount2,$itemnum,$type,$user);
289   }
290   if ($type eq 'N'){
291     $desc.="New Card";
292   }
293   if ($type eq 'F'){
294     $desc.="Fine";
295   }
296   if ($type eq 'A'){
297     $desc.="Account Management fee";
298   }
299   if ($type eq 'M'){
300     $desc.="Sundry";
301   }     
302         
303   if ($type eq 'L' && $desc eq ''){
304     
305     $desc="Lost Item";
306   }
307   if ($type eq 'REF'){
308     $desc.="Cash Refund";    
309     $amountleft=refund('',$borrowernumber,$amount);
310   }
311   if(($type eq 'L') or ($type eq 'F') or ($type eq 'A') or ($type eq 'N') or ($type eq 'M') ){
312   $notifyid=1;  
313   }
314     
315   if ($itemnum ne ''){
316     $desc.=" ".$itemnum;
317     my $sth=$dbh->prepare("INSERT INTO  accountlines
318                         (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding, itemnumber,notify_id)
319         VALUES (?, ?, now(), ?,?, ?,?,?,?)");
320 #     $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft, $data->{'itemnumber'});
321      $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft, $itemnum,$notifyid);
322   } else {
323     my $sth=$dbh->prepare("INSERT INTO  accountlines
324             (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding,notify_id)
325             VALUES (?, ?, now(), ?, ?, ?, ?,?)");
326     $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft,$notifyid);
327   }
328 }
329
330 =head2 fixcredit
331
332  $amountleft = &fixcredit($borrowernumber, $data, $barcode, $type, $user);
333
334  This function is only used internally, not exported.
335  FIXME - Figure out what this function does, and write it down.
336
337 =cut
338
339 sub fixcredit{
340   #here we update both the accountoffsets and the account lines
341   my ($borrowernumber,$data,$barcode,$type,$user)=@_;
342   my $dbh = C4::Context->dbh;
343   my $newamtos = 0;
344   my $accdata = "";
345   my $amountleft = $data;
346   if ($barcode ne ''){
347     my $item=GetBiblioFromItemNumber('',$barcode);
348     my $nextaccntno = getnextacctno($borrowernumber);
349     my $query="Select * from accountlines where (borrowernumber=?
350     and itemnumber=? and amountoutstanding > 0)";
351     if ($type eq 'CL'){
352       $query.=" and (accounttype = 'L' or accounttype = 'Rep')";
353     } elsif ($type eq 'CF'){
354       $query.=" and (accounttype = 'F' or accounttype = 'FU' or
355       accounttype='Res' or accounttype='Rent')";
356     } elsif ($type eq 'CB'){
357       $query.=" and accounttype='A'";
358     }
359 #    print $query;
360     my $sth=$dbh->prepare($query);
361     $sth->execute($borrowernumber,$item->{'itemnumber'});
362     $accdata=$sth->fetchrow_hashref;
363     $sth->finish;
364     if ($accdata->{'amountoutstanding'} < $amountleft) {
365         $newamtos = 0;
366         $amountleft -= $accdata->{'amountoutstanding'};
367      }  else {
368         $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
369         $amountleft = 0;
370      }
371           my $thisacct = $accdata->{accountno};
372      my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
373      where (borrowernumber = ?) and (accountno=?)");
374      $usth->execute($newamtos,$borrowernumber,$thisacct);
375      $usth->finish;
376      $usth = $dbh->prepare("insert into accountoffsets
377      (borrowernumber, accountno, offsetaccount,  offsetamount)
378      values (?,?,?,?)");
379      $usth->execute($borrowernumber,$accdata->{'accountno'},$nextaccntno,$newamtos);
380      $usth->finish;
381   }
382   # begin transaction
383   my $nextaccntno = getnextacctno($borrowernumber);
384   # get lines with outstanding amounts to offset
385   my $sth = $dbh->prepare("select * from accountlines
386   where (borrowernumber = ?) and (amountoutstanding >0)
387   order by date");
388   $sth->execute($borrowernumber);
389 #  print $query;
390   # offset transactions
391   while (($accdata=$sth->fetchrow_hashref) and ($amountleft>0)){
392      if ($accdata->{'amountoutstanding'} < $amountleft) {
393         $newamtos = 0;
394         $amountleft -= $accdata->{'amountoutstanding'};
395      }  else {
396         $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
397         $amountleft = 0;
398      }
399      my $thisacct = $accdata->{accountno};
400      my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
401      where (borrowernumber = ?) and (accountno=?)");
402      $usth->execute($newamtos,$borrowernumber,$thisacct);
403      $usth->finish;
404      $usth = $dbh->prepare("insert into accountoffsets
405      (borrowernumber, accountno, offsetaccount,  offsetamount)
406      values (?,?,?,?)");
407      $usth->execute($borrowernumber,$accdata->{'accountno'},$nextaccntno,$newamtos);
408      $usth->finish;
409   }
410   $sth->finish;
411   $type="Credit ".$type;
412   UpdateStats($user,$type,$data,$user,'','',$borrowernumber);
413   $amountleft*=-1;
414   return($amountleft);
415
416 }
417
418 =head2 refund
419
420 # FIXME - Figure out what this function does, and write it down.
421
422 =cut 
423
424 sub refund{
425   #here we update both the accountoffsets and the account lines
426   my ($borrowernumber,$data)=@_;
427   my $dbh = C4::Context->dbh;
428   my $newamtos = 0;
429   my $accdata = "";
430   my $amountleft = $data *-1;
431
432   # begin transaction
433   my $nextaccntno = getnextacctno($borrowernumber);
434   # get lines with outstanding amounts to offset
435   my $sth = $dbh->prepare("select * from accountlines
436   where (borrowernumber = ?) and (amountoutstanding<0)
437   order by date");
438   $sth->execute($borrowernumber);
439 #  print $amountleft;
440   # offset transactions
441   while (($accdata=$sth->fetchrow_hashref) and ($amountleft<0)){
442      if ($accdata->{'amountoutstanding'} > $amountleft) {
443         $newamtos = 0;
444         $amountleft -= $accdata->{'amountoutstanding'};
445      }  else {
446         $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
447         $amountleft = 0;
448      }
449 #     print $amountleft;
450      my $thisacct = $accdata->{accountno};
451      my $usth = $dbh->prepare("update accountlines set amountoutstanding= ?
452      where (borrowernumber = ?) and (accountno=?)");
453      $usth->execute($newamtos,$borrowernumber,$thisacct);
454      $usth->finish;
455      $usth = $dbh->prepare("insert into accountoffsets
456      (borrowernumber, accountno, offsetaccount,  offsetamount)
457      values (?,?,?,?)");
458      $usth->execute($borrowernumber,$accdata->{'accountno'},$nextaccntno,$newamtos);
459      $usth->finish;
460   }
461   $sth->finish;
462   return($amountleft);
463 }
464
465
466 END { }       # module clean-up code here (global destructor)
467
468 1;
469 __END__
470
471
472 =head1 SEE ALSO
473
474 DBI(3)
475
476 =cut
477