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
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
22 #use warnings; FIXME - Bug 2505
26 use C4
::Circulation
qw(ReturnLostItem);
27 use C4
::Log
qw(logaction);
29 use Data
::Dumper
qw(Dumper);
31 use vars
qw(@ISA @EXPORT);
34 # set the version for version checking
49 &recordpayment_selectaccts
51 &purge_zero_balance_fees
57 C4::Accounts - Functions for dealing with Koha accounts
65 The functions in this module deal with the monetary aspect of Koha,
66 including looking up and modifying the amount of money owed by a
73 &recordpayment($borrowernumber, $payment, $sip_paytype, $note);
75 Record payment by a patron. C<$borrowernumber> is the patron's
76 borrower number. C<$payment> is a floating-point number, giving the
77 amount that was paid. C<$sip_paytype> is an optional flag to indicate this
78 payment was made over a SIP2 interface, rather than the staff client. The
79 value passed is the SIP2 payment type value (message 37, characters 21-22)
81 Amounts owed are paid off oldest first. That is, if the patron has a
82 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
83 of $1.50, then the oldest fine will be paid off in full, and $0.50
84 will be credited to the next one.
91 #here we update the account lines
92 my ( $borrowernumber, $data, $sip_paytype, $payment_note ) = @_;
93 my $dbh = C4
::Context
->dbh;
96 my $branch = C4
::Context
->userenv->{'branch'};
97 my $amountleft = $data;
99 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
101 $payment_note //= "";
104 my $nextaccntno = getnextacctno
($borrowernumber);
106 # get lines with outstanding amounts to offset
107 my $sth = $dbh->prepare(
108 "SELECT * FROM accountlines
109 WHERE (borrowernumber = ?) AND (amountoutstanding<>0)
112 $sth->execute($borrowernumber);
114 # offset transactions
116 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft > 0 ) ) {
117 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
119 $amountleft -= $accdata->{'amountoutstanding'};
122 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
125 my $thisacct = $accdata->{accountlines_id
};
126 my $usth = $dbh->prepare(
127 "UPDATE accountlines SET amountoutstanding= ?
128 WHERE (accountlines_id = ?)"
130 $usth->execute( $newamtos, $thisacct );
132 if ( C4
::Context
->preference("FinesLog") ) {
133 $accdata->{'amountoutstanding_new'} = $newamtos;
134 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
135 action
=> 'fee_payment',
136 borrowernumber
=> $accdata->{'borrowernumber'},
137 old_amountoutstanding
=> $accdata->{'amountoutstanding'},
138 new_amountoutstanding
=> $newamtos,
139 amount_paid
=> $accdata->{'amountoutstanding'} - $newamtos,
140 accountlines_id
=> $accdata->{'accountlines_id'},
141 accountno
=> $accdata->{'accountno'},
142 manager_id
=> $manager_id,
143 note
=> $payment_note,
145 push( @ids, $accdata->{'accountlines_id'} );
150 my $usth = $dbh->prepare(
151 "INSERT INTO accountlines
152 (borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding,manager_id, note)
153 VALUES (?,?,now(),?,'',?,?,?,?)"
157 $paytype .= $sip_paytype if defined $sip_paytype;
158 $usth->execute( $borrowernumber, $nextaccntno, 0 - $data, $paytype, 0 - $amountleft, $manager_id, $payment_note );
165 borrowernumber
=> $borrowernumber,
166 accountno
=> $nextaccntno }
169 if ( C4
::Context
->preference("FinesLog") ) {
170 $accdata->{'amountoutstanding_new'} = $newamtos;
171 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
172 action
=> 'create_payment',
173 borrowernumber
=> $borrowernumber,
174 accountno
=> $nextaccntno,
175 amount
=> $data * -1,
176 amountoutstanding
=> $amountleft * -1,
177 accounttype
=> 'Pay',
178 accountlines_paid
=> \
@ids,
179 manager_id
=> $manager_id,
187 &makepayment($accountlines_id, $borrowernumber, $acctnumber, $amount, $branchcode);
189 Records the fact that a patron has paid off the entire amount he or
192 C<$borrowernumber> is the patron's borrower number. C<$acctnumber> is
193 the account that was credited. C<$amount> is the amount paid (this is
194 only used to record the payment. It is assumed to be equal to the
195 amount owed). C<$branchcode> is the code of the branch where payment
201 # FIXME - I'm not at all sure about the above, because I don't
202 # understand what the acct* tables in the Koha database are for.
205 #here we update both the accountoffsets and the account lines
206 #updated to check, if they are paying off a lost item, we return the item
207 # from their card, and put a note on the item record
208 my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_;
209 my $dbh = C4
::Context
->dbh;
211 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
214 my $nextaccntno = getnextacctno
($borrowernumber);
216 my $sth = $dbh->prepare("SELECT * FROM accountlines WHERE accountlines_id=?");
217 $sth->execute( $accountlines_id );
218 my $data = $sth->fetchrow_hashref;
221 if ( $data->{'accounttype'} eq "Pay" ){
225 SET amountoutstanding = 0
226 WHERE accountlines_id = ?
229 $udp->execute($accountlines_id);
234 SET amountoutstanding = 0
235 WHERE accountlines_id = ?
238 $udp->execute($accountlines_id);
241 my $payment = 0 - $amount;
242 $payment_note //= "";
247 INTO accountlines (borrowernumber, accountno, date, amount, itemnumber, description, accounttype, amountoutstanding, manager_id, note)
248 VALUES ( ?, ?, now(), ?, ?, '', 'Pay', 0, ?, ?)"
250 $ins->execute($borrowernumber, $nextaccntno, $payment, $data->{'itemnumber'}, $manager_id, $payment_note);
253 if ( C4
::Context
->preference("FinesLog") ) {
254 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
255 action
=> 'fee_payment',
256 borrowernumber
=> $borrowernumber,
257 old_amountoutstanding
=> $data->{'amountoutstanding'},
258 new_amountoutstanding
=> 0,
259 amount_paid
=> $data->{'amountoutstanding'},
260 accountlines_id
=> $data->{'accountlines_id'},
261 accountno
=> $data->{'accountno'},
262 manager_id
=> $manager_id,
266 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
267 action
=> 'create_payment',
268 borrowernumber
=> $borrowernumber,
269 accountno
=> $nextaccntno,
271 amountoutstanding
=> 0,,
272 accounttype
=> 'Pay',
273 accountlines_paid
=> [$data->{'accountlines_id'}],
274 manager_id
=> $manager_id,
282 borrowernumber
=> $borrowernumber,
283 accountno
=> $accountno
286 #check to see what accounttype
287 if ( $data->{'accounttype'} eq 'Rep' || $data->{'accounttype'} eq 'L' ) {
288 C4
::Circulation
::ReturnLostItem
( $borrowernumber, $data->{'itemnumber'} );
290 my $sthr = $dbh->prepare("SELECT max(accountlines_id) AS lastinsertid FROM accountlines");
292 my $datalastinsertid = $sthr->fetchrow_hashref;
293 return $datalastinsertid->{'lastinsertid'};
298 $nextacct = &getnextacctno($borrowernumber);
300 Returns the next unused account number for the patron with the given
306 # FIXME - Okay, so what does the above actually _mean_?
308 my ($borrowernumber) = shift or return;
309 my $sth = C4
::Context
->dbh->prepare(
310 "SELECT accountno+1 FROM accountlines
311 WHERE (borrowernumber = ?)
312 ORDER BY accountno DESC
315 $sth->execute($borrowernumber);
316 return ($sth->fetchrow || 1);
319 =head2 fixaccounts (removed)
321 &fixaccounts($accountlines_id, $borrowernumber, $accountnumber, $amount);
324 # FIXME - I don't understand what this function does.
326 my ( $accountlines_id, $borrowernumber, $accountno, $amount ) = @_;
327 my $dbh = C4::Context->dbh;
328 my $sth = $dbh->prepare(
329 "SELECT * FROM accountlines WHERE accountlines_id=?"
331 $sth->execute( $accountlines_id );
332 my $data = $sth->fetchrow_hashref;
334 # FIXME - Error-checking
335 my $diff = $amount - $data->{'amount'};
336 my $outstanding = $data->{'amountoutstanding'} + $diff;
341 SET amount = '$amount',
342 amountoutstanding = '$outstanding'
343 WHERE accountlines_id = $accountlines_id
345 # FIXME: exceedingly bad form. Use prepare with placholders ("?") in query and execute args.
351 # lost ==1 Lost, lost==2 longoverdue, lost==3 lost and paid for
352 # FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that
353 # a charge has been added
354 # FIXME : if no replacement price, borrower just doesn't get charged?
355 my $dbh = C4
::Context
->dbh();
356 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
358 # first make sure the borrower hasn't already been charged for this item
359 my $sth1=$dbh->prepare("SELECT * from accountlines
360 WHERE borrowernumber=? AND itemnumber=? and accounttype='L'");
361 $sth1->execute($borrowernumber,$itemnumber);
362 my $existing_charge_hashref=$sth1->fetchrow_hashref();
365 unless ($existing_charge_hashref) {
367 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
368 # This item is on issue ... add replacement cost to the borrower's record and mark it returned
369 # Note that we add this to the account even if there's no replacement price, allowing some other
370 # process (or person) to update it, since we don't handle any defaults for replacement prices.
371 my $accountno = getnextacctno
($borrowernumber);
372 my $sth2=$dbh->prepare("INSERT INTO accountlines
373 (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding,itemnumber,manager_id)
374 VALUES (?,?,now(),?,?,'L',?,?,?)");
375 $sth2->execute($borrowernumber,$accountno,$amount,
376 $description,$amount,$itemnumber,$manager_id);
378 if ( C4
::Context
->preference("FinesLog") ) {
379 logaction
("FINES", 'CREATE', $borrowernumber, Dumper
({
380 action
=> 'create_fee',
381 borrowernumber
=> $borrowernumber,
382 accountno
=> $accountno,
384 amountoutstanding
=> $amount,
385 description
=> $description,
387 itemnumber
=> $itemnumber,
388 manager_id
=> $manager_id,
397 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
400 C<$borrowernumber> is the patron's borrower number.
401 C<$description> is a description of the transaction.
402 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
404 C<$itemnumber> is the item involved, if pertinent; otherwise, it
405 should be the empty string.
410 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
413 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
416 # 'A' = Account Management fee
422 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
424 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
425 my $dbh = C4
::Context
->dbh;
428 my $accountno = getnextacctno
($borrowernumber);
429 my $amountleft = $amount;
431 if ( ( $type eq 'L' )
435 or ( $type eq 'M' ) )
441 $desc .= ' ' . $itemnum;
442 my $sth = $dbh->prepare(
443 'INSERT INTO accountlines
444 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding, itemnumber,notify_id, note, manager_id)
445 VALUES (?, ?, now(), ?,?, ?,?,?,?,?,?)');
446 $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft, $itemnum,$notifyid, $note, $manager_id) || return $sth->errstr;
448 my $sth=$dbh->prepare("INSERT INTO accountlines
449 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding,notify_id, note, manager_id)
450 VALUES (?, ?, now(), ?, ?, ?, ?,?,?,?)"
452 $sth->execute( $borrowernumber, $accountno, $amount, $desc, $type,
453 $amountleft, $notifyid, $note, $manager_id );
456 if ( C4
::Context
->preference("FinesLog") ) {
457 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
458 action
=> 'create_fee',
459 borrowernumber
=> $borrowernumber,
460 accountno
=> $accountno,
462 description
=> $desc,
463 accounttype
=> $type,
464 amountoutstanding
=> $amountleft,
465 notify_id
=> $notifyid,
467 itemnumber
=> $itemnum,
468 manager_id
=> $manager_id,
476 my ( $borrowerno, $timestamp, $accountno ) = @_;
477 my $dbh = C4
::Context
->dbh;
478 my $timestamp2 = $timestamp - 1;
480 my $sth = $dbh->prepare(
481 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
483 $sth->execute( $borrowerno, $accountno );
486 while ( my $data = $sth->fetchrow_hashref ) {
493 my ( $accountlines_id, $note ) = @_;
494 my $dbh = C4
::Context
->dbh;
495 my $sth = $dbh->prepare('UPDATE accountlines SET note = ? WHERE accountlines_id = ?');
496 $sth->execute( $note, $accountlines_id );
500 my ( $date, $date2 ) = @_;
501 my $dbh = C4
::Context
->dbh;
502 my $sth = $dbh->prepare(
503 "SELECT * FROM accountlines,borrowers
504 WHERE amount < 0 AND accounttype not like 'Pay%' AND accountlines.borrowernumber = borrowers.borrowernumber
505 AND timestamp >=TIMESTAMP(?) AND timestamp < TIMESTAMP(?)"
508 $sth->execute( $date, $date2 );
510 while ( my $data = $sth->fetchrow_hashref ) {
511 $data->{'date'} = $data->{'timestamp'};
519 my ( $date, $date2 ) = @_;
520 my $dbh = C4
::Context
->dbh;
522 my $sth = $dbh->prepare(
523 "SELECT *,timestamp AS datetime
524 FROM accountlines,borrowers
525 WHERE (accounttype = 'REF'
526 AND accountlines.borrowernumber = borrowers.borrowernumber
527 AND date >=? AND date <?)"
530 $sth->execute( $date, $date2 );
533 while ( my $data = $sth->fetchrow_hashref ) {
541 my ( $accountlines_id ) = @_;
542 my $dbh = C4
::Context
->dbh;
544 my $sth = $dbh->prepare('SELECT * FROM accountlines WHERE accountlines_id = ?');
545 $sth->execute( $accountlines_id );
546 my $row = $sth->fetchrow_hashref();
547 my $amount_outstanding = $row->{'amountoutstanding'};
549 if ( $amount_outstanding <= 0 ) {
550 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = amount * -1, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?');
551 $sth->execute( $accountlines_id );
553 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = 0, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?');
554 $sth->execute( $accountlines_id );
557 if ( C4
::Context
->preference("FinesLog") ) {
559 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
561 if ( $amount_outstanding <= 0 ) {
562 $row->{'amountoutstanding'} *= -1;
564 $row->{'amountoutstanding'} = '0';
566 $row->{'description'} .= ' Reversed -';
567 logaction
("FINES", 'MODIFY', $row->{'borrowernumber'}, Dumper
({
568 action
=> 'reverse_fee_payment',
569 borrowernumber
=> $row->{'borrowernumber'},
570 old_amountoutstanding
=> $row->{'amountoutstanding'},
571 new_amountoutstanding
=> 0 - $amount_outstanding,,
572 accountlines_id
=> $row->{'accountlines_id'},
573 accountno
=> $row->{'accountno'},
574 manager_id
=> $manager_id,
581 =head2 recordpayment_selectaccts
583 recordpayment_selectaccts($borrowernumber, $payment,$accts);
585 Record payment by a patron. C<$borrowernumber> is the patron's
586 borrower number. C<$payment> is a floating-point number, giving the
587 amount that was paid. C<$accts> is an array ref to a list of
588 accountnos which the payment can be recorded against
590 Amounts owed are paid off oldest first. That is, if the patron has a
591 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
592 of $1.50, then the oldest fine will be paid off in full, and $0.50
593 will be credited to the next one.
597 sub recordpayment_selectaccts
{
598 my ( $borrowernumber, $amount, $accts, $note ) = @_;
600 my $dbh = C4
::Context
->dbh;
603 my $branch = C4
::Context
->userenv->{branch
};
604 my $amountleft = $amount;
606 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
607 my $sql = 'SELECT * FROM accountlines WHERE (borrowernumber = ?) ' .
608 'AND (amountoutstanding<>0) ';
610 $sql .= ' AND accountno IN ( ' . join ',', @
{$accts};
613 $sql .= ' ORDER BY date';
615 my $nextaccntno = getnextacctno
($borrowernumber);
617 # get lines with outstanding amounts to offset
618 my $rows = $dbh->selectall_arrayref($sql, { Slice
=> {} }, $borrowernumber);
620 # offset transactions
621 my $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding= ? ' .
622 'WHERE accountlines_id=?');
625 for my $accdata ( @
{$rows} ) {
626 if ($amountleft == 0) {
629 if ( $accdata->{amountoutstanding
} < $amountleft ) {
631 $amountleft -= $accdata->{amountoutstanding
};
634 $newamtos = $accdata->{amountoutstanding
} - $amountleft;
637 my $thisacct = $accdata->{accountlines_id
};
638 $sth->execute( $newamtos, $thisacct );
640 if ( C4
::Context
->preference("FinesLog") ) {
641 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
642 action
=> 'fee_payment',
643 borrowernumber
=> $borrowernumber,
644 old_amountoutstanding
=> $accdata->{'amountoutstanding'},
645 new_amountoutstanding
=> $newamtos,
646 amount_paid
=> $accdata->{'amountoutstanding'} - $newamtos,
647 accountlines_id
=> $accdata->{'accountlines_id'},
648 accountno
=> $accdata->{'accountno'},
649 manager_id
=> $manager_id,
651 push( @ids, $accdata->{'accountlines_id'} );
657 $sql = 'INSERT INTO accountlines ' .
658 '(borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding,manager_id,note) ' .
659 q
|VALUES
(?
,?
,now
(),?
,'','Pay',?
,?
,?
)|;
660 $dbh->do($sql,{},$borrowernumber, $nextaccntno, 0 - $amount, 0 - $amountleft, $manager_id, $note );
665 borrowernumber
=> $borrowernumber,
666 accountno
=> $nextaccntno}
669 if ( C4
::Context
->preference("FinesLog") ) {
670 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
671 action
=> 'create_payment',
672 borrowernumber
=> $borrowernumber,
673 accountno
=> $nextaccntno,
674 amount
=> 0 - $amount,
675 amountoutstanding
=> 0 - $amountleft,
676 accounttype
=> 'Pay',
677 accountlines_paid
=> \
@ids,
678 manager_id
=> $manager_id,
685 # makepayment needs to be fixed to handle partials till then this separate subroutine
687 sub makepartialpayment
{
688 my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_;
690 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
691 if (!$amount || $amount < 0) {
694 $payment_note //= "";
695 my $dbh = C4
::Context
->dbh;
697 my $nextaccntno = getnextacctno
($borrowernumber);
700 my $data = $dbh->selectrow_hashref(
701 'SELECT * FROM accountlines WHERE accountlines_id=?',undef,$accountlines_id);
702 my $new_outstanding = $data->{amountoutstanding
} - $amount;
704 my $update = 'UPDATE accountlines SET amountoutstanding = ? WHERE accountlines_id = ? ';
705 $dbh->do( $update, undef, $new_outstanding, $accountlines_id);
707 if ( C4
::Context
->preference("FinesLog") ) {
708 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
709 action
=> 'fee_payment',
710 borrowernumber
=> $borrowernumber,
711 old_amountoutstanding
=> $data->{'amountoutstanding'},
712 new_amountoutstanding
=> $new_outstanding,
713 amount_paid
=> $data->{'amountoutstanding'} - $new_outstanding,
714 accountlines_id
=> $data->{'accountlines_id'},
715 accountno
=> $data->{'accountno'},
716 manager_id
=> $manager_id,
721 my $insert = 'INSERT INTO accountlines (borrowernumber, accountno, date, amount, '
722 . 'description, accounttype, amountoutstanding, itemnumber, manager_id, note) '
723 . ' VALUES (?, ?, now(), ?, ?, ?, 0, ?, ?, ?)';
725 $dbh->do( $insert, undef, $borrowernumber, $nextaccntno, $amount,
726 '', 'Pay', $data->{'itemnumber'}, $manager_id, $payment_note);
732 borrowernumber
=> $borrowernumber,
733 accountno
=> $accountno
736 if ( C4
::Context
->preference("FinesLog") ) {
737 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
738 action
=> 'create_payment',
739 borrowernumber
=> $user,
740 accountno
=> $nextaccntno,
741 amount
=> 0 - $amount,
742 accounttype
=> 'Pay',
743 itemnumber
=> $data->{'itemnumber'},
744 accountlines_paid
=> [ $data->{'accountlines_id'} ],
745 manager_id
=> $manager_id,
754 WriteOffFee( $borrowernumber, $accountline_id, $itemnum, $accounttype, $amount, $branch, $payment_note );
756 Write off a fine for a patron.
757 C<$borrowernumber> is the patron's borrower number.
758 C<$accountline_id> is the accountline_id of the fee to write off.
759 C<$itemnum> is the itemnumber of of item whose fine is being written off.
760 C<$accounttype> is the account type of the fine being written off.
761 C<$amount> is a floating-point number, giving the amount that is being written off.
762 C<$branch> is the branchcode of the library where the writeoff occurred.
763 C<$payment_note> is the note to attach to this payment
768 my ( $borrowernumber, $accountlines_id, $itemnum, $accounttype, $amount, $branch, $payment_note ) = @_;
769 $payment_note //= "";
770 $branch ||= C4
::Context
->userenv->{branch
};
772 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
774 # if no item is attached to fine, make sure to store it as a NULL
778 my $dbh = C4
::Context
->dbh();
781 UPDATE accountlines SET amountoutstanding = 0
782 WHERE accountlines_id = ? AND borrowernumber = ?
784 $sth = $dbh->prepare( $query );
785 $sth->execute( $accountlines_id, $borrowernumber );
787 if ( C4
::Context
->preference("FinesLog") ) {
788 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
789 action
=> 'fee_writeoff',
790 borrowernumber
=> $borrowernumber,
791 accountlines_id
=> $accountlines_id,
792 manager_id
=> $manager_id,
797 INSERT INTO accountlines
798 ( borrowernumber, accountno, itemnumber, date, amount, description, accounttype, manager_id, note )
799 VALUES ( ?, ?, ?, NOW(), ?, 'Writeoff', 'W', ?, ? )
801 $sth = $dbh->prepare( $query );
802 my $acct = getnextacctno
($borrowernumber);
803 $sth->execute( $borrowernumber, $acct, $itemnum, $amount, $manager_id, $payment_note );
805 if ( C4
::Context
->preference("FinesLog") ) {
806 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
807 action
=> 'create_writeoff',
808 borrowernumber
=> $borrowernumber,
810 amount
=> 0 - $amount,
812 itemnumber
=> $itemnum,
813 accountlines_paid
=> [ $accountlines_id ],
814 manager_id
=> $manager_id,
822 borrowernumber
=> $borrowernumber}
827 =head2 purge_zero_balance_fees
829 purge_zero_balance_fees( $days );
831 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
833 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
835 B<Warning:> Because fines and payments are not linked in accountlines, it is
836 possible for a fine to be deleted without the accompanying payment,
837 or vise versa. This won't affect the account balance, but might be
842 sub purge_zero_balance_fees
{
846 my $dbh = C4
::Context
->dbh;
847 my $sth = $dbh->prepare(
849 DELETE FROM accountlines
850 WHERE date < date_sub(curdate(), INTERVAL ? DAY)
851 AND ( amountoutstanding = 0 or amountoutstanding IS NULL );
854 $sth->execute($days) or die $dbh->errstr;
857 END { } # module clean-up code here (global destructor)