Bug 7753: serials-home displays library name instead of code
[koha.git] / C4 / Accounts.pm
blobb7aef01ec8b49962a909f082fa8eb6d736d2ce87
1 package C4::Accounts;
3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
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.
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.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 use strict;
22 #use warnings; FIXME - Bug 2505
23 use C4::Context;
24 use C4::Stats;
25 use C4::Members;
26 use C4::Circulation qw(ReturnLostItem);
28 use vars qw($VERSION @ISA @EXPORT);
30 BEGIN {
31 # set the version for version checking
32 $VERSION = 3.03;
33 require Exporter;
34 @ISA = qw(Exporter);
35 @EXPORT = qw(
36 &recordpayment
37 &makepayment
38 &manualinvoice
39 &getnextacctno
40 &reconcileaccount
41 &getcharges
42 &ModNote
43 &getcredits
44 &getrefunds
45 &chargelostitem
46 &ReversePayment
47 &makepartialpayment
48 &recordpayment_selectaccts
49 &WriteOffFee
53 =head1 NAME
55 C4::Accounts - Functions for dealing with Koha accounts
57 =head1 SYNOPSIS
59 use C4::Accounts;
61 =head1 DESCRIPTION
63 The functions in this module deal with the monetary aspect of Koha,
64 including looking up and modifying the amount of money owed by a
65 patron.
67 =head1 FUNCTIONS
69 =head2 recordpayment
71 &recordpayment($borrowernumber, $payment);
73 Record payment by a patron. C<$borrowernumber> is the patron's
74 borrower number. C<$payment> is a floating-point number, giving the
75 amount that was paid.
77 Amounts owed are paid off oldest first. That is, if the patron has a
78 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
79 of $1.50, then the oldest fine will be paid off in full, and $0.50
80 will be credited to the next one.
82 =cut
85 sub recordpayment {
87 #here we update the account lines
88 my ( $borrowernumber, $data ) = @_;
89 my $dbh = C4::Context->dbh;
90 my $newamtos = 0;
91 my $accdata = "";
92 my $branch = C4::Context->userenv->{'branch'};
93 my $amountleft = $data;
95 # begin transaction
96 my $nextaccntno = getnextacctno($borrowernumber);
98 # get lines with outstanding amounts to offset
99 my $sth = $dbh->prepare(
100 "SELECT * FROM accountlines
101 WHERE (borrowernumber = ?) AND (amountoutstanding<>0)
102 ORDER BY date"
104 $sth->execute($borrowernumber);
106 # offset transactions
107 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft > 0 ) ) {
108 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
109 $newamtos = 0;
110 $amountleft -= $accdata->{'amountoutstanding'};
112 else {
113 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
114 $amountleft = 0;
116 my $thisacct = $accdata->{accountno};
117 my $usth = $dbh->prepare(
118 "UPDATE accountlines SET amountoutstanding= ?
119 WHERE (borrowernumber = ?) AND (accountno=?)"
121 $usth->execute( $newamtos, $borrowernumber, $thisacct );
122 $usth->finish;
123 # $usth = $dbh->prepare(
124 # "INSERT INTO accountoffsets
125 # (borrowernumber, accountno, offsetaccount, offsetamount)
126 # VALUES (?,?,?,?)"
127 # );
128 # $usth->execute( $borrowernumber, $accdata->{'accountno'},
129 # $nextaccntno, $newamtos );
130 $usth->finish;
133 # create new line
134 my $usth = $dbh->prepare(
135 "INSERT INTO accountlines
136 (borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding)
137 VALUES (?,?,now(),?,'Payment,thanks','Pay',?)"
139 $usth->execute( $borrowernumber, $nextaccntno, 0 - $data, 0 - $amountleft );
140 $usth->finish;
141 UpdateStats( $branch, 'payment', $data, '', '', '', $borrowernumber, $nextaccntno );
142 $sth->finish;
145 =head2 makepayment
147 &makepayment($borrowernumber, $acctnumber, $amount, $branchcode);
149 Records the fact that a patron has paid off the entire amount he or
150 she owes.
152 C<$borrowernumber> is the patron's borrower number. C<$acctnumber> is
153 the account that was credited. C<$amount> is the amount paid (this is
154 only used to record the payment. It is assumed to be equal to the
155 amount owed). C<$branchcode> is the code of the branch where payment
156 was made.
158 =cut
161 # FIXME - I'm not at all sure about the above, because I don't
162 # understand what the acct* tables in the Koha database are for.
163 sub makepayment {
165 #here we update both the accountoffsets and the account lines
166 #updated to check, if they are paying off a lost item, we return the item
167 # from their card, and put a note on the item record
168 my ( $borrowernumber, $accountno, $amount, $user, $branch ) = @_;
169 my $dbh = C4::Context->dbh;
170 my $manager_id = 0;
171 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
173 # begin transaction
174 my $nextaccntno = getnextacctno($borrowernumber);
175 my $newamtos = 0;
176 my $sth =
177 $dbh->prepare(
178 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno=?");
179 $sth->execute( $borrowernumber, $accountno );
180 my $data = $sth->fetchrow_hashref;
181 $sth->finish;
183 if($data->{'accounttype'} eq "Pay"){
184 my $udp =
185 $dbh->prepare(
186 "UPDATE accountlines
187 SET amountoutstanding = 0, description = 'Payment,thanks'
188 WHERE borrowernumber = ?
189 AND accountno = ?
192 $udp->execute($borrowernumber, $accountno );
193 $udp->finish;
194 }else{
195 my $udp =
196 $dbh->prepare(
197 "UPDATE accountlines
198 SET amountoutstanding = 0
199 WHERE borrowernumber = ?
200 AND accountno = ?
203 $udp->execute($borrowernumber, $accountno );
204 $udp->finish;
206 # create new line
207 my $payment = 0 - $amount;
209 my $ins =
210 $dbh->prepare(
211 "INSERT
212 INTO accountlines (borrowernumber, accountno, date, amount, itemnumber, description, accounttype, amountoutstanding, manager_id)
213 VALUES ( ?, ?, now(), ?, ?, 'Payment,thanks', 'Pay', 0, ?)"
215 $ins->execute($borrowernumber, $nextaccntno, $payment, $data->{'itemnumber'}, $manager_id);
216 $ins->finish;
219 # FIXME - The second argument to &UpdateStats is supposed to be the
220 # branch code.
221 # UpdateStats is now being passed $accountno too. MTJ
222 UpdateStats( $user, 'payment', $amount, '', '', '', $borrowernumber,
223 $accountno );
224 #from perldoc: for SELECT only #$sth->finish;
226 #check to see what accounttype
227 if ( $data->{'accounttype'} eq 'Rep' || $data->{'accounttype'} eq 'L' ) {
228 C4::Circulation::ReturnLostItem( $borrowernumber, $data->{'itemnumber'} );
232 =head2 getnextacctno
234 $nextacct = &getnextacctno($borrowernumber);
236 Returns the next unused account number for the patron with the given
237 borrower number.
239 =cut
242 # FIXME - Okay, so what does the above actually _mean_?
243 sub getnextacctno ($) {
244 my ($borrowernumber) = shift or return undef;
245 my $sth = C4::Context->dbh->prepare(
246 "SELECT accountno+1 FROM accountlines
247 WHERE (borrowernumber = ?)
248 ORDER BY accountno DESC
249 LIMIT 1"
251 $sth->execute($borrowernumber);
252 return ($sth->fetchrow || 1);
255 =head2 fixaccounts (removed)
257 &fixaccounts($borrowernumber, $accountnumber, $amount);
260 # FIXME - I don't understand what this function does.
261 sub fixaccounts {
262 my ( $borrowernumber, $accountno, $amount ) = @_;
263 my $dbh = C4::Context->dbh;
264 my $sth = $dbh->prepare(
265 "SELECT * FROM accountlines WHERE borrowernumber=?
266 AND accountno=?"
268 $sth->execute( $borrowernumber, $accountno );
269 my $data = $sth->fetchrow_hashref;
271 # FIXME - Error-checking
272 my $diff = $amount - $data->{'amount'};
273 my $outstanding = $data->{'amountoutstanding'} + $diff;
274 $sth->finish;
276 $dbh->do(<<EOT);
277 UPDATE accountlines
278 SET amount = '$amount',
279 amountoutstanding = '$outstanding'
280 WHERE borrowernumber = $borrowernumber
281 AND accountno = $accountno
283 # FIXME: exceedingly bad form. Use prepare with placholders ("?") in query and execute args.
286 =cut
288 sub chargelostitem{
289 # lost ==1 Lost, lost==2 longoverdue, lost==3 lost and paid for
290 # FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that
291 # a charge has been added
292 # FIXME : if no replacement price, borrower just doesn't get charged?
293 my $dbh = C4::Context->dbh();
294 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
296 # first make sure the borrower hasn't already been charged for this item
297 my $sth1=$dbh->prepare("SELECT * from accountlines
298 WHERE borrowernumber=? AND itemnumber=? and accounttype='L'");
299 $sth1->execute($borrowernumber,$itemnumber);
300 my $existing_charge_hashref=$sth1->fetchrow_hashref();
302 # OK, they haven't
303 unless ($existing_charge_hashref) {
304 # This item is on issue ... add replacement cost to the borrower's record and mark it returned
305 # Note that we add this to the account even if there's no replacement price, allowing some other
306 # process (or person) to update it, since we don't handle any defaults for replacement prices.
307 my $accountno = getnextacctno($borrowernumber);
308 my $sth2=$dbh->prepare("INSERT INTO accountlines
309 (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding,itemnumber)
310 VALUES (?,?,now(),?,?,'L',?,?)");
311 $sth2->execute($borrowernumber,$accountno,$amount,
312 $description,$amount,$itemnumber);
313 $sth2->finish;
314 # FIXME: Log this ?
318 =head2 manualinvoice
320 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
321 $amount, $note);
323 C<$borrowernumber> is the patron's borrower number.
324 C<$description> is a description of the transaction.
325 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
326 or C<REF>.
327 C<$itemnumber> is the item involved, if pertinent; otherwise, it
328 should be the empty string.
330 =cut
333 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
334 # are :
335 # 'C' = CREDIT
336 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
337 # 'N' = New Card fee
338 # 'F' = Fine
339 # 'A' = Account Management fee
340 # 'M' = Sundry
341 # 'L' = Lost Item
344 sub manualinvoice {
345 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
346 my $manager_id = 0;
347 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
348 my $dbh = C4::Context->dbh;
349 my $notifyid = 0;
350 my $insert;
351 my $accountno = getnextacctno($borrowernumber);
352 my $amountleft = $amount;
354 # if ( $type eq 'CS'
355 # || $type eq 'CB'
356 # || $type eq 'CW'
357 # || $type eq 'CF'
358 # || $type eq 'CL' )
360 # my $amount2 = $amount * -1; # FIXME - $amount2 = -$amount
361 # $amountleft =
362 # fixcredit( $borrowernumber, $amount2, $itemnum, $type, $user );
364 if ( $type eq 'N' ) {
365 $desc .= " New Card";
367 if ( $type eq 'F' ) {
368 $desc .= " Fine";
370 if ( $type eq 'A' ) {
371 $desc .= " Account Management fee";
373 if ( $type eq 'M' ) {
374 $desc .= " Sundry";
377 if ( $type eq 'L' && $desc eq '' ) {
379 $desc = " Lost Item";
381 # if ( $type eq 'REF' ) {
382 # $desc .= " Cash Refund";
383 # $amountleft = refund( '', $borrowernumber, $amount );
385 if ( ( $type eq 'L' )
386 or ( $type eq 'F' )
387 or ( $type eq 'A' )
388 or ( $type eq 'N' )
389 or ( $type eq 'M' ) )
391 $notifyid = 1;
394 if ( $itemnum ) {
395 $desc .= ' ' . $itemnum;
396 my $sth = $dbh->prepare(
397 'INSERT INTO accountlines
398 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding, itemnumber,notify_id, note, manager_id)
399 VALUES (?, ?, now(), ?,?, ?,?,?,?,?,?)');
400 $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft, $itemnum,$notifyid, $note, $manager_id) || return $sth->errstr;
401 } else {
402 my $sth=$dbh->prepare("INSERT INTO accountlines
403 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding,notify_id, note, manager_id)
404 VALUES (?, ?, now(), ?, ?, ?, ?,?,?,?)"
406 $sth->execute( $borrowernumber, $accountno, $amount, $desc, $type,
407 $amountleft, $notifyid, $note, $manager_id );
409 return 0;
412 =head2 fixcredit #### DEPRECATED
414 $amountleft = &fixcredit($borrowernumber, $data, $barcode, $type, $user);
416 This function is only used internally, not exported.
418 =cut
420 # This function is deprecated in 3.0
422 sub fixcredit {
424 #here we update both the accountoffsets and the account lines
425 my ( $borrowernumber, $data, $barcode, $type, $user ) = @_;
426 my $dbh = C4::Context->dbh;
427 my $newamtos = 0;
428 my $accdata = "";
429 my $amountleft = $data;
430 if ( $barcode ne '' ) {
431 my $item = GetBiblioFromItemNumber( '', $barcode );
432 my $nextaccntno = getnextacctno($borrowernumber);
433 my $query = "SELECT * FROM accountlines WHERE (borrowernumber=?
434 AND itemnumber=? AND amountoutstanding > 0)";
435 if ( $type eq 'CL' ) {
436 $query .= " AND (accounttype = 'L' OR accounttype = 'Rep')";
438 elsif ( $type eq 'CF' ) {
439 $query .= " AND (accounttype = 'F' OR accounttype = 'FU' OR
440 accounttype='Res' OR accounttype='Rent')";
442 elsif ( $type eq 'CB' ) {
443 $query .= " and accounttype='A'";
446 # print $query;
447 my $sth = $dbh->prepare($query);
448 $sth->execute( $borrowernumber, $item->{'itemnumber'} );
449 $accdata = $sth->fetchrow_hashref;
450 $sth->finish;
451 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
452 $newamtos = 0;
453 $amountleft -= $accdata->{'amountoutstanding'};
455 else {
456 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
457 $amountleft = 0;
459 my $thisacct = $accdata->{accountno};
460 my $usth = $dbh->prepare(
461 "UPDATE accountlines SET amountoutstanding= ?
462 WHERE (borrowernumber = ?) AND (accountno=?)"
464 $usth->execute( $newamtos, $borrowernumber, $thisacct );
465 $usth->finish;
466 $usth = $dbh->prepare(
467 "INSERT INTO accountoffsets
468 (borrowernumber, accountno, offsetaccount, offsetamount)
469 VALUES (?,?,?,?)"
471 $usth->execute( $borrowernumber, $accdata->{'accountno'},
472 $nextaccntno, $newamtos );
473 $usth->finish;
476 # begin transaction
477 my $nextaccntno = getnextacctno($borrowernumber);
479 # get lines with outstanding amounts to offset
480 my $sth = $dbh->prepare(
481 "SELECT * FROM accountlines
482 WHERE (borrowernumber = ?) AND (amountoutstanding >0)
483 ORDER BY date"
485 $sth->execute($borrowernumber);
487 # print $query;
488 # offset transactions
489 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft > 0 ) ) {
490 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
491 $newamtos = 0;
492 $amountleft -= $accdata->{'amountoutstanding'};
494 else {
495 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
496 $amountleft = 0;
498 my $thisacct = $accdata->{accountno};
499 my $usth = $dbh->prepare(
500 "UPDATE accountlines SET amountoutstanding= ?
501 WHERE (borrowernumber = ?) AND (accountno=?)"
503 $usth->execute( $newamtos, $borrowernumber, $thisacct );
504 $usth->finish;
505 $usth = $dbh->prepare(
506 "INSERT INTO accountoffsets
507 (borrowernumber, accountno, offsetaccount, offsetamount)
508 VALUE (?,?,?,?)"
510 $usth->execute( $borrowernumber, $accdata->{'accountno'},
511 $nextaccntno, $newamtos );
512 $usth->finish;
514 $sth->finish;
515 $type = "Credit " . $type;
516 UpdateStats( $user, $type, $data, $user, '', '', $borrowernumber );
517 $amountleft *= -1;
518 return ($amountleft);
522 =head2 refund
524 #FIXME : DEPRECATED SUB
525 This subroutine tracks payments and/or credits against fines/charges
526 using the accountoffsets table, which is not used consistently in
527 Koha's fines management, and so is not used in 3.0
529 =cut
531 sub refund {
533 #here we update both the accountoffsets and the account lines
534 my ( $borrowernumber, $data ) = @_;
535 my $dbh = C4::Context->dbh;
536 my $newamtos = 0;
537 my $accdata = "";
538 my $amountleft = $data * -1;
540 # begin transaction
541 my $nextaccntno = getnextacctno($borrowernumber);
543 # get lines with outstanding amounts to offset
544 my $sth = $dbh->prepare(
545 "SELECT * FROM accountlines
546 WHERE (borrowernumber = ?) AND (amountoutstanding<0)
547 ORDER BY date"
549 $sth->execute($borrowernumber);
551 # print $amountleft;
552 # offset transactions
553 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft < 0 ) ) {
554 if ( $accdata->{'amountoutstanding'} > $amountleft ) {
555 $newamtos = 0;
556 $amountleft -= $accdata->{'amountoutstanding'};
558 else {
559 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
560 $amountleft = 0;
563 # print $amountleft;
564 my $thisacct = $accdata->{accountno};
565 my $usth = $dbh->prepare(
566 "UPDATE accountlines SET amountoutstanding= ?
567 WHERE (borrowernumber = ?) AND (accountno=?)"
569 $usth->execute( $newamtos, $borrowernumber, $thisacct );
570 $usth->finish;
571 $usth = $dbh->prepare(
572 "INSERT INTO accountoffsets
573 (borrowernumber, accountno, offsetaccount, offsetamount)
574 VALUES (?,?,?,?)"
576 $usth->execute( $borrowernumber, $accdata->{'accountno'},
577 $nextaccntno, $newamtos );
578 $usth->finish;
580 $sth->finish;
581 return ($amountleft);
584 sub getcharges {
585 my ( $borrowerno, $timestamp, $accountno ) = @_;
586 my $dbh = C4::Context->dbh;
587 my $timestamp2 = $timestamp - 1;
588 my $query = "";
589 my $sth = $dbh->prepare(
590 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
592 $sth->execute( $borrowerno, $accountno );
594 my @results;
595 while ( my $data = $sth->fetchrow_hashref ) {
596 push @results,$data;
598 return (@results);
601 sub ModNote {
602 my ( $borrowernumber, $accountno, $note ) = @_;
603 my $dbh = C4::Context->dbh;
604 my $sth = $dbh->prepare('UPDATE accountlines SET note = ? WHERE borrowernumber = ? AND accountno = ?');
605 $sth->execute( $note, $borrowernumber, $accountno );
608 sub getcredits {
609 my ( $date, $date2 ) = @_;
610 my $dbh = C4::Context->dbh;
611 my $sth = $dbh->prepare(
612 "SELECT * FROM accountlines,borrowers
613 WHERE amount < 0 AND accounttype <> 'Pay' AND accountlines.borrowernumber = borrowers.borrowernumber
614 AND timestamp >=TIMESTAMP(?) AND timestamp < TIMESTAMP(?)"
617 $sth->execute( $date, $date2 );
618 my @results;
619 while ( my $data = $sth->fetchrow_hashref ) {
620 $data->{'date'} = $data->{'timestamp'};
621 push @results,$data;
623 return (@results);
627 sub getrefunds {
628 my ( $date, $date2 ) = @_;
629 my $dbh = C4::Context->dbh;
631 my $sth = $dbh->prepare(
632 "SELECT *,timestamp AS datetime
633 FROM accountlines,borrowers
634 WHERE (accounttype = 'REF'
635 AND accountlines.borrowernumber = borrowers.borrowernumber
636 AND date >=? AND date <?)"
639 $sth->execute( $date, $date2 );
641 my @results;
642 while ( my $data = $sth->fetchrow_hashref ) {
643 push @results,$data;
646 return (@results);
649 sub ReversePayment {
650 my ( $borrowernumber, $accountno ) = @_;
651 my $dbh = C4::Context->dbh;
653 my $sth = $dbh->prepare('SELECT amountoutstanding FROM accountlines WHERE borrowernumber = ? AND accountno = ?');
654 $sth->execute( $borrowernumber, $accountno );
655 my $row = $sth->fetchrow_hashref();
656 my $amount_outstanding = $row->{'amountoutstanding'};
658 if ( $amount_outstanding <= 0 ) {
659 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = amount * -1, description = CONCAT( description, " Reversed -" ) WHERE borrowernumber = ? AND accountno = ?');
660 $sth->execute( $borrowernumber, $accountno );
661 } else {
662 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = 0, description = CONCAT( description, " Reversed -" ) WHERE borrowernumber = ? AND accountno = ?');
663 $sth->execute( $borrowernumber, $accountno );
667 =head2 recordpayment_selectaccts
669 recordpayment_selectaccts($borrowernumber, $payment,$accts);
671 Record payment by a patron. C<$borrowernumber> is the patron's
672 borrower number. C<$payment> is a floating-point number, giving the
673 amount that was paid. C<$accts> is an array ref to a list of
674 accountnos which the payment can be recorded against
676 Amounts owed are paid off oldest first. That is, if the patron has a
677 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
678 of $1.50, then the oldest fine will be paid off in full, and $0.50
679 will be credited to the next one.
681 =cut
683 sub recordpayment_selectaccts {
684 my ( $borrowernumber, $amount, $accts ) = @_;
686 my $dbh = C4::Context->dbh;
687 my $newamtos = 0;
688 my $accdata = q{};
689 my $branch = C4::Context->userenv->{branch};
690 my $amountleft = $amount;
691 my $sql = 'SELECT * FROM accountlines WHERE (borrowernumber = ?) ' .
692 'AND (amountoutstanding<>0) ';
693 if (@{$accts} ) {
694 $sql .= ' AND accountno IN ( ' . join ',', @{$accts};
695 $sql .= ' ) ';
697 $sql .= ' ORDER BY date';
698 # begin transaction
699 my $nextaccntno = getnextacctno($borrowernumber);
701 # get lines with outstanding amounts to offset
702 my $rows = $dbh->selectall_arrayref($sql, { Slice => {} }, $borrowernumber);
704 # offset transactions
705 my $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding= ? ' .
706 'WHERE (borrowernumber = ?) AND (accountno=?)');
707 for my $accdata ( @{$rows} ) {
708 if ($amountleft == 0) {
709 last;
711 if ( $accdata->{amountoutstanding} < $amountleft ) {
712 $newamtos = 0;
713 $amountleft -= $accdata->{amountoutstanding};
715 else {
716 $newamtos = $accdata->{amountoutstanding} - $amountleft;
717 $amountleft = 0;
719 my $thisacct = $accdata->{accountno};
720 $sth->execute( $newamtos, $borrowernumber, $thisacct );
723 # create new line
724 $sql = 'INSERT INTO accountlines ' .
725 '(borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding) ' .
726 q|VALUES (?,?,now(),?,'Payment,thanks','Pay',?)|;
727 $dbh->do($sql,{},$borrowernumber, $nextaccntno, 0 - $amount, 0 - $amountleft );
728 UpdateStats( $branch, 'payment', $amount, '', '', '', $borrowernumber, $nextaccntno );
729 return;
732 # makepayment needs to be fixed to handle partials till then this separate subroutine
733 # fills in
734 sub makepartialpayment {
735 my ( $borrowernumber, $accountno, $amount, $user, $branch ) = @_;
736 my $manager_id = 0;
737 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
738 if (!$amount || $amount < 0) {
739 return;
741 my $dbh = C4::Context->dbh;
743 my $nextaccntno = getnextacctno($borrowernumber);
744 my $newamtos = 0;
746 my $data = $dbh->selectrow_hashref(
747 'SELECT * FROM accountlines WHERE borrowernumber=? AND accountno=?',undef,$borrowernumber,$accountno);
748 my $new_outstanding = $data->{amountoutstanding} - $amount;
750 my $update = 'UPDATE accountlines SET amountoutstanding = ? WHERE borrowernumber = ? '
751 . ' AND accountno = ?';
752 $dbh->do( $update, undef, $new_outstanding, $borrowernumber, $accountno);
754 # create new line
755 my $insert = 'INSERT INTO accountlines (borrowernumber, accountno, date, amount, '
756 . 'description, accounttype, amountoutstanding, itemnumber, manager_id) '
757 . ' VALUES (?, ?, now(), ?, ?, ?, 0, ?, ?)';
759 $dbh->do( $insert, undef, $borrowernumber, $nextaccntno, $amount,
760 "Payment, thanks - $user", 'Pay', $data->{'itemnumber'}, $manager_id);
762 UpdateStats( $user, 'payment', $amount, '', '', '', $borrowernumber, $accountno );
764 return;
767 =head2 WriteOff
769 WriteOff( $borrowernumber, $accountnum, $itemnum, $accounttype, $amount, $branch );
771 Write off a fine for a patron.
772 C<$borrowernumber> is the patron's borrower number.
773 C<$accountnum> is the accountnumber of the fee to write off.
774 C<$itemnum> is the itemnumber of of item whose fine is being written off.
775 C<$accounttype> is the account type of the fine being written off.
776 C<$amount> is a floating-point number, giving the amount that is being written off.
777 C<$branch> is the branchcode of the library where the writeoff occurred.
779 =cut
781 sub WriteOffFee {
782 my ( $borrowernumber, $accountnum, $itemnum, $accounttype, $amount, $branch ) = @_;
783 $branch ||= C4::Context->userenv->{branch};
784 my $manager_id = 0;
785 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
787 # if no item is attached to fine, make sure to store it as a NULL
788 $itemnum ||= undef;
790 my ( $sth, $query );
791 my $dbh = C4::Context->dbh();
793 $query = "
794 UPDATE accountlines SET amountoutstanding = 0
795 WHERE accountno = ? AND borrowernumber = ?
797 $sth = $dbh->prepare( $query );
798 $sth->execute( $accountnum, $borrowernumber );
800 $query ="
801 INSERT INTO accountlines
802 ( borrowernumber, accountno, itemnumber, date, amount, description, accounttype, manager_id )
803 VALUES ( ?, ?, ?, NOW(), ?, 'Writeoff', 'W', ? )
805 $sth = $dbh->prepare( $query );
806 my $acct = getnextacctno($borrowernumber);
807 $sth->execute( $borrowernumber, $acct, $itemnum, $amount, $manager_id );
809 UpdateStats( $branch, 'writeoff', $amount, q{}, q{}, q{}, $borrowernumber );
813 END { } # module clean-up code here (global destructor)
816 __END__
818 =head1 SEE ALSO
820 DBI(3)
822 =cut