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($VERSION @ISA @EXPORT);
34 # set the version for version checking
35 $VERSION = 3.07.00.049;
50 &recordpayment_selectaccts
52 &purge_zero_balance_fees
58 C4::Accounts - Functions for dealing with Koha accounts
66 The functions in this module deal with the monetary aspect of Koha,
67 including looking up and modifying the amount of money owed by a
74 &recordpayment($borrowernumber, $payment, $sip_paytype, $note);
76 Record payment by a patron. C<$borrowernumber> is the patron's
77 borrower number. C<$payment> is a floating-point number, giving the
78 amount that was paid. C<$sip_paytype> is an optional flag to indicate this
79 payment was made over a SIP2 interface, rather than the staff client. The
80 value passed is the SIP2 payment type value (message 37, characters 21-22)
82 Amounts owed are paid off oldest first. That is, if the patron has a
83 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
84 of $1.50, then the oldest fine will be paid off in full, and $0.50
85 will be credited to the next one.
92 #here we update the account lines
93 my ( $borrowernumber, $data, $sip_paytype, $payment_note ) = @_;
94 my $dbh = C4
::Context
->dbh;
97 my $branch = C4
::Context
->userenv->{'branch'};
98 my $amountleft = $data;
100 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
102 $payment_note //= "";
105 my $nextaccntno = getnextacctno
($borrowernumber);
107 # get lines with outstanding amounts to offset
108 my $sth = $dbh->prepare(
109 "SELECT * FROM accountlines
110 WHERE (borrowernumber = ?) AND (amountoutstanding<>0)
113 $sth->execute($borrowernumber);
115 # offset transactions
117 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft > 0 ) ) {
118 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
120 $amountleft -= $accdata->{'amountoutstanding'};
123 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
126 my $thisacct = $accdata->{accountlines_id
};
127 my $usth = $dbh->prepare(
128 "UPDATE accountlines SET amountoutstanding= ?
129 WHERE (accountlines_id = ?)"
131 $usth->execute( $newamtos, $thisacct );
133 if ( C4
::Context
->preference("FinesLog") ) {
134 $accdata->{'amountoutstanding_new'} = $newamtos;
135 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
136 action
=> 'fee_payment',
137 borrowernumber
=> $accdata->{'borrowernumber'},
138 old_amountoutstanding
=> $accdata->{'amountoutstanding'},
139 new_amountoutstanding
=> $newamtos,
140 amount_paid
=> $accdata->{'amountoutstanding'} - $newamtos,
141 accountlines_id
=> $accdata->{'accountlines_id'},
142 accountno
=> $accdata->{'accountno'},
143 manager_id
=> $manager_id,
144 note
=> $payment_note,
146 push( @ids, $accdata->{'accountlines_id'} );
151 my $usth = $dbh->prepare(
152 "INSERT INTO accountlines
153 (borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding,manager_id, note)
154 VALUES (?,?,now(),?,'',?,?,?,?)"
158 $paytype .= $sip_paytype if defined $sip_paytype;
159 $usth->execute( $borrowernumber, $nextaccntno, 0 - $data, $paytype, 0 - $amountleft, $manager_id, $payment_note );
166 borrowernumber
=> $borrowernumber,
167 accountno
=> $nextaccntno }
170 if ( C4
::Context
->preference("FinesLog") ) {
171 $accdata->{'amountoutstanding_new'} = $newamtos;
172 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
173 action
=> 'create_payment',
174 borrowernumber
=> $borrowernumber,
175 accountno
=> $nextaccntno,
176 amount
=> $data * -1,
177 amountoutstanding
=> $amountleft * -1,
178 accounttype
=> 'Pay',
179 accountlines_paid
=> \
@ids,
180 manager_id
=> $manager_id,
188 &makepayment($accountlines_id, $borrowernumber, $acctnumber, $amount, $branchcode);
190 Records the fact that a patron has paid off the entire amount he or
193 C<$borrowernumber> is the patron's borrower number. C<$acctnumber> is
194 the account that was credited. C<$amount> is the amount paid (this is
195 only used to record the payment. It is assumed to be equal to the
196 amount owed). C<$branchcode> is the code of the branch where payment
202 # FIXME - I'm not at all sure about the above, because I don't
203 # understand what the acct* tables in the Koha database are for.
206 #here we update both the accountoffsets and the account lines
207 #updated to check, if they are paying off a lost item, we return the item
208 # from their card, and put a note on the item record
209 my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_;
210 my $dbh = C4
::Context
->dbh;
212 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
215 my $nextaccntno = getnextacctno
($borrowernumber);
217 my $sth = $dbh->prepare("SELECT * FROM accountlines WHERE accountlines_id=?");
218 $sth->execute( $accountlines_id );
219 my $data = $sth->fetchrow_hashref;
222 if ( $data->{'accounttype'} eq "Pay" ){
226 SET amountoutstanding = 0
227 WHERE accountlines_id = ?
230 $udp->execute($accountlines_id);
235 SET amountoutstanding = 0
236 WHERE accountlines_id = ?
239 $udp->execute($accountlines_id);
242 my $payment = 0 - $amount;
243 $payment_note //= "";
248 INTO accountlines (borrowernumber, accountno, date, amount, itemnumber, description, accounttype, amountoutstanding, manager_id, note)
249 VALUES ( ?, ?, now(), ?, ?, '', 'Pay', 0, ?, ?)"
251 $ins->execute($borrowernumber, $nextaccntno, $payment, $data->{'itemnumber'}, $manager_id, $payment_note);
254 if ( C4
::Context
->preference("FinesLog") ) {
255 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
256 action
=> 'fee_payment',
257 borrowernumber
=> $borrowernumber,
258 old_amountoutstanding
=> $data->{'amountoutstanding'},
259 new_amountoutstanding
=> 0,
260 amount_paid
=> $data->{'amountoutstanding'},
261 accountlines_id
=> $data->{'accountlines_id'},
262 accountno
=> $data->{'accountno'},
263 manager_id
=> $manager_id,
267 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
268 action
=> 'create_payment',
269 borrowernumber
=> $borrowernumber,
270 accountno
=> $nextaccntno,
272 amountoutstanding
=> 0,,
273 accounttype
=> 'Pay',
274 accountlines_paid
=> [$data->{'accountlines_id'}],
275 manager_id
=> $manager_id,
283 borrowernumber
=> $borrowernumber,
284 accountno
=> $accountno
287 #check to see what accounttype
288 if ( $data->{'accounttype'} eq 'Rep' || $data->{'accounttype'} eq 'L' ) {
289 C4
::Circulation
::ReturnLostItem
( $borrowernumber, $data->{'itemnumber'} );
291 my $sthr = $dbh->prepare("SELECT max(accountlines_id) AS lastinsertid FROM accountlines");
293 my $datalastinsertid = $sthr->fetchrow_hashref;
294 return $datalastinsertid->{'lastinsertid'};
299 $nextacct = &getnextacctno($borrowernumber);
301 Returns the next unused account number for the patron with the given
307 # FIXME - Okay, so what does the above actually _mean_?
309 my ($borrowernumber) = shift or return;
310 my $sth = C4
::Context
->dbh->prepare(
311 "SELECT accountno+1 FROM accountlines
312 WHERE (borrowernumber = ?)
313 ORDER BY accountno DESC
316 $sth->execute($borrowernumber);
317 return ($sth->fetchrow || 1);
320 =head2 fixaccounts (removed)
322 &fixaccounts($accountlines_id, $borrowernumber, $accountnumber, $amount);
325 # FIXME - I don't understand what this function does.
327 my ( $accountlines_id, $borrowernumber, $accountno, $amount ) = @_;
328 my $dbh = C4::Context->dbh;
329 my $sth = $dbh->prepare(
330 "SELECT * FROM accountlines WHERE accountlines_id=?"
332 $sth->execute( $accountlines_id );
333 my $data = $sth->fetchrow_hashref;
335 # FIXME - Error-checking
336 my $diff = $amount - $data->{'amount'};
337 my $outstanding = $data->{'amountoutstanding'} + $diff;
342 SET amount = '$amount',
343 amountoutstanding = '$outstanding'
344 WHERE accountlines_id = $accountlines_id
346 # FIXME: exceedingly bad form. Use prepare with placholders ("?") in query and execute args.
352 # lost ==1 Lost, lost==2 longoverdue, lost==3 lost and paid for
353 # FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that
354 # a charge has been added
355 # FIXME : if no replacement price, borrower just doesn't get charged?
356 my $dbh = C4
::Context
->dbh();
357 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
359 # first make sure the borrower hasn't already been charged for this item
360 my $sth1=$dbh->prepare("SELECT * from accountlines
361 WHERE borrowernumber=? AND itemnumber=? and accounttype='L'");
362 $sth1->execute($borrowernumber,$itemnumber);
363 my $existing_charge_hashref=$sth1->fetchrow_hashref();
366 unless ($existing_charge_hashref) {
368 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
369 # This item is on issue ... add replacement cost to the borrower's record and mark it returned
370 # Note that we add this to the account even if there's no replacement price, allowing some other
371 # process (or person) to update it, since we don't handle any defaults for replacement prices.
372 my $accountno = getnextacctno
($borrowernumber);
373 my $sth2=$dbh->prepare("INSERT INTO accountlines
374 (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding,itemnumber,manager_id)
375 VALUES (?,?,now(),?,?,'L',?,?,?)");
376 $sth2->execute($borrowernumber,$accountno,$amount,
377 $description,$amount,$itemnumber,$manager_id);
379 if ( C4
::Context
->preference("FinesLog") ) {
380 logaction
("FINES", 'CREATE', $borrowernumber, Dumper
({
381 action
=> 'create_fee',
382 borrowernumber
=> $borrowernumber,
383 accountno
=> $accountno,
385 amountoutstanding
=> $amount,
386 description
=> $description,
388 itemnumber
=> $itemnumber,
389 manager_id
=> $manager_id,
398 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
401 C<$borrowernumber> is the patron's borrower number.
402 C<$description> is a description of the transaction.
403 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
405 C<$itemnumber> is the item involved, if pertinent; otherwise, it
406 should be the empty string.
411 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
414 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
417 # 'A' = Account Management fee
423 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
425 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
426 my $dbh = C4
::Context
->dbh;
429 my $accountno = getnextacctno
($borrowernumber);
430 my $amountleft = $amount;
432 if ( ( $type eq 'L' )
436 or ( $type eq 'M' ) )
442 $desc .= ' ' . $itemnum;
443 my $sth = $dbh->prepare(
444 'INSERT INTO accountlines
445 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding, itemnumber,notify_id, note, manager_id)
446 VALUES (?, ?, now(), ?,?, ?,?,?,?,?,?)');
447 $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft, $itemnum,$notifyid, $note, $manager_id) || return $sth->errstr;
449 my $sth=$dbh->prepare("INSERT INTO accountlines
450 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding,notify_id, note, manager_id)
451 VALUES (?, ?, now(), ?, ?, ?, ?,?,?,?)"
453 $sth->execute( $borrowernumber, $accountno, $amount, $desc, $type,
454 $amountleft, $notifyid, $note, $manager_id );
457 if ( C4
::Context
->preference("FinesLog") ) {
458 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
459 action
=> 'create_fee',
460 borrowernumber
=> $borrowernumber,
461 accountno
=> $accountno,
463 description
=> $desc,
464 accounttype
=> $type,
465 amountoutstanding
=> $amountleft,
466 notify_id
=> $notifyid,
468 itemnumber
=> $itemnum,
469 manager_id
=> $manager_id,
477 my ( $borrowerno, $timestamp, $accountno ) = @_;
478 my $dbh = C4
::Context
->dbh;
479 my $timestamp2 = $timestamp - 1;
481 my $sth = $dbh->prepare(
482 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
484 $sth->execute( $borrowerno, $accountno );
487 while ( my $data = $sth->fetchrow_hashref ) {
494 my ( $accountlines_id, $note ) = @_;
495 my $dbh = C4
::Context
->dbh;
496 my $sth = $dbh->prepare('UPDATE accountlines SET note = ? WHERE accountlines_id = ?');
497 $sth->execute( $note, $accountlines_id );
501 my ( $date, $date2 ) = @_;
502 my $dbh = C4
::Context
->dbh;
503 my $sth = $dbh->prepare(
504 "SELECT * FROM accountlines,borrowers
505 WHERE amount < 0 AND accounttype not like 'Pay%' AND accountlines.borrowernumber = borrowers.borrowernumber
506 AND timestamp >=TIMESTAMP(?) AND timestamp < TIMESTAMP(?)"
509 $sth->execute( $date, $date2 );
511 while ( my $data = $sth->fetchrow_hashref ) {
512 $data->{'date'} = $data->{'timestamp'};
520 my ( $date, $date2 ) = @_;
521 my $dbh = C4
::Context
->dbh;
523 my $sth = $dbh->prepare(
524 "SELECT *,timestamp AS datetime
525 FROM accountlines,borrowers
526 WHERE (accounttype = 'REF'
527 AND accountlines.borrowernumber = borrowers.borrowernumber
528 AND date >=? AND date <?)"
531 $sth->execute( $date, $date2 );
534 while ( my $data = $sth->fetchrow_hashref ) {
542 my ( $accountlines_id ) = @_;
543 my $dbh = C4
::Context
->dbh;
545 my $sth = $dbh->prepare('SELECT * FROM accountlines WHERE accountlines_id = ?');
546 $sth->execute( $accountlines_id );
547 my $row = $sth->fetchrow_hashref();
548 my $amount_outstanding = $row->{'amountoutstanding'};
550 if ( $amount_outstanding <= 0 ) {
551 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = amount * -1, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?');
552 $sth->execute( $accountlines_id );
554 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = 0, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?');
555 $sth->execute( $accountlines_id );
558 if ( C4
::Context
->preference("FinesLog") ) {
560 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
562 if ( $amount_outstanding <= 0 ) {
563 $row->{'amountoutstanding'} *= -1;
565 $row->{'amountoutstanding'} = '0';
567 $row->{'description'} .= ' Reversed -';
568 logaction
("FINES", 'MODIFY', $row->{'borrowernumber'}, Dumper
({
569 action
=> 'reverse_fee_payment',
570 borrowernumber
=> $row->{'borrowernumber'},
571 old_amountoutstanding
=> $row->{'amountoutstanding'},
572 new_amountoutstanding
=> 0 - $amount_outstanding,,
573 accountlines_id
=> $row->{'accountlines_id'},
574 accountno
=> $row->{'accountno'},
575 manager_id
=> $manager_id,
582 =head2 recordpayment_selectaccts
584 recordpayment_selectaccts($borrowernumber, $payment,$accts);
586 Record payment by a patron. C<$borrowernumber> is the patron's
587 borrower number. C<$payment> is a floating-point number, giving the
588 amount that was paid. C<$accts> is an array ref to a list of
589 accountnos which the payment can be recorded against
591 Amounts owed are paid off oldest first. That is, if the patron has a
592 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
593 of $1.50, then the oldest fine will be paid off in full, and $0.50
594 will be credited to the next one.
598 sub recordpayment_selectaccts
{
599 my ( $borrowernumber, $amount, $accts, $note ) = @_;
601 my $dbh = C4
::Context
->dbh;
604 my $branch = C4
::Context
->userenv->{branch
};
605 my $amountleft = $amount;
607 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
608 my $sql = 'SELECT * FROM accountlines WHERE (borrowernumber = ?) ' .
609 'AND (amountoutstanding<>0) ';
611 $sql .= ' AND accountno IN ( ' . join ',', @
{$accts};
614 $sql .= ' ORDER BY date';
616 my $nextaccntno = getnextacctno
($borrowernumber);
618 # get lines with outstanding amounts to offset
619 my $rows = $dbh->selectall_arrayref($sql, { Slice
=> {} }, $borrowernumber);
621 # offset transactions
622 my $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding= ? ' .
623 'WHERE accountlines_id=?');
626 for my $accdata ( @
{$rows} ) {
627 if ($amountleft == 0) {
630 if ( $accdata->{amountoutstanding
} < $amountleft ) {
632 $amountleft -= $accdata->{amountoutstanding
};
635 $newamtos = $accdata->{amountoutstanding
} - $amountleft;
638 my $thisacct = $accdata->{accountlines_id
};
639 $sth->execute( $newamtos, $thisacct );
641 if ( C4
::Context
->preference("FinesLog") ) {
642 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
643 action
=> 'fee_payment',
644 borrowernumber
=> $borrowernumber,
645 old_amountoutstanding
=> $accdata->{'amountoutstanding'},
646 new_amountoutstanding
=> $newamtos,
647 amount_paid
=> $accdata->{'amountoutstanding'} - $newamtos,
648 accountlines_id
=> $accdata->{'accountlines_id'},
649 accountno
=> $accdata->{'accountno'},
650 manager_id
=> $manager_id,
652 push( @ids, $accdata->{'accountlines_id'} );
658 $sql = 'INSERT INTO accountlines ' .
659 '(borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding,manager_id,note) ' .
660 q
|VALUES
(?
,?
,now
(),?
,'','Pay',?
,?
,?
)|;
661 $dbh->do($sql,{},$borrowernumber, $nextaccntno, 0 - $amount, 0 - $amountleft, $manager_id, $note );
666 borrowernumber
=> $borrowernumber,
667 accountno
=> $nextaccntno}
670 if ( C4
::Context
->preference("FinesLog") ) {
671 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
672 action
=> 'create_payment',
673 borrowernumber
=> $borrowernumber,
674 accountno
=> $nextaccntno,
675 amount
=> 0 - $amount,
676 amountoutstanding
=> 0 - $amountleft,
677 accounttype
=> 'Pay',
678 accountlines_paid
=> \
@ids,
679 manager_id
=> $manager_id,
686 # makepayment needs to be fixed to handle partials till then this separate subroutine
688 sub makepartialpayment
{
689 my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_;
691 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
692 if (!$amount || $amount < 0) {
695 $payment_note //= "";
696 my $dbh = C4
::Context
->dbh;
698 my $nextaccntno = getnextacctno
($borrowernumber);
701 my $data = $dbh->selectrow_hashref(
702 'SELECT * FROM accountlines WHERE accountlines_id=?',undef,$accountlines_id);
703 my $new_outstanding = $data->{amountoutstanding
} - $amount;
705 my $update = 'UPDATE accountlines SET amountoutstanding = ? WHERE accountlines_id = ? ';
706 $dbh->do( $update, undef, $new_outstanding, $accountlines_id);
708 if ( C4
::Context
->preference("FinesLog") ) {
709 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
710 action
=> 'fee_payment',
711 borrowernumber
=> $borrowernumber,
712 old_amountoutstanding
=> $data->{'amountoutstanding'},
713 new_amountoutstanding
=> $new_outstanding,
714 amount_paid
=> $data->{'amountoutstanding'} - $new_outstanding,
715 accountlines_id
=> $data->{'accountlines_id'},
716 accountno
=> $data->{'accountno'},
717 manager_id
=> $manager_id,
722 my $insert = 'INSERT INTO accountlines (borrowernumber, accountno, date, amount, '
723 . 'description, accounttype, amountoutstanding, itemnumber, manager_id, note) '
724 . ' VALUES (?, ?, now(), ?, ?, ?, 0, ?, ?, ?)';
726 $dbh->do( $insert, undef, $borrowernumber, $nextaccntno, $amount,
727 '', 'Pay', $data->{'itemnumber'}, $manager_id, $payment_note);
733 borrowernumber
=> $borrowernumber,
734 accountno
=> $accountno
737 if ( C4
::Context
->preference("FinesLog") ) {
738 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
739 action
=> 'create_payment',
740 borrowernumber
=> $user,
741 accountno
=> $nextaccntno,
742 amount
=> 0 - $amount,
743 accounttype
=> 'Pay',
744 itemnumber
=> $data->{'itemnumber'},
745 accountlines_paid
=> [ $data->{'accountlines_id'} ],
746 manager_id
=> $manager_id,
755 WriteOffFee( $borrowernumber, $accountline_id, $itemnum, $accounttype, $amount, $branch, $payment_note );
757 Write off a fine for a patron.
758 C<$borrowernumber> is the patron's borrower number.
759 C<$accountline_id> is the accountline_id of the fee to write off.
760 C<$itemnum> is the itemnumber of of item whose fine is being written off.
761 C<$accounttype> is the account type of the fine being written off.
762 C<$amount> is a floating-point number, giving the amount that is being written off.
763 C<$branch> is the branchcode of the library where the writeoff occurred.
764 C<$payment_note> is the note to attach to this payment
769 my ( $borrowernumber, $accountlines_id, $itemnum, $accounttype, $amount, $branch, $payment_note ) = @_;
770 $payment_note //= "";
771 $branch ||= C4
::Context
->userenv->{branch
};
773 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
775 # if no item is attached to fine, make sure to store it as a NULL
779 my $dbh = C4
::Context
->dbh();
782 UPDATE accountlines SET amountoutstanding = 0
783 WHERE accountlines_id = ? AND borrowernumber = ?
785 $sth = $dbh->prepare( $query );
786 $sth->execute( $accountlines_id, $borrowernumber );
788 if ( C4
::Context
->preference("FinesLog") ) {
789 logaction
("FINES", 'MODIFY', $borrowernumber, Dumper
({
790 action
=> 'fee_writeoff',
791 borrowernumber
=> $borrowernumber,
792 accountlines_id
=> $accountlines_id,
793 manager_id
=> $manager_id,
798 INSERT INTO accountlines
799 ( borrowernumber, accountno, itemnumber, date, amount, description, accounttype, manager_id, note )
800 VALUES ( ?, ?, ?, NOW(), ?, 'Writeoff', 'W', ?, ? )
802 $sth = $dbh->prepare( $query );
803 my $acct = getnextacctno
($borrowernumber);
804 $sth->execute( $borrowernumber, $acct, $itemnum, $amount, $manager_id, $payment_note );
806 if ( C4
::Context
->preference("FinesLog") ) {
807 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
808 action
=> 'create_writeoff',
809 borrowernumber
=> $borrowernumber,
811 amount
=> 0 - $amount,
813 itemnumber
=> $itemnum,
814 accountlines_paid
=> [ $accountlines_id ],
815 manager_id
=> $manager_id,
823 borrowernumber
=> $borrowernumber}
828 =head2 purge_zero_balance_fees
830 purge_zero_balance_fees( $days );
832 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
834 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
836 B<Warning:> Because fines and payments are not linked in accountlines, it is
837 possible for a fine to be deleted without the accompanying payment,
838 or vise versa. This won't affect the account balance, but might be
843 sub purge_zero_balance_fees
{
847 my $dbh = C4
::Context
->dbh;
848 my $sth = $dbh->prepare(
850 DELETE FROM accountlines
851 WHERE date < date_sub(curdate(), INTERVAL ? DAY)
852 AND ( amountoutstanding = 0 or amountoutstanding IS NULL );
855 $sth->execute($days) or die $dbh->errstr;
858 END { } # module clean-up code here (global destructor)