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
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.
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;
51 &recordpayment_selectaccts
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);
76 Record payment by a patron. C<$borrowernumber> is the patron's
77 borrower number. C<$payment> is a floating-point number, giving the
80 Amounts owed are paid off oldest first. That is, if the patron has a
81 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
82 of $1.50, then the oldest fine will be paid off in full, and $0.50
83 will be credited to the next one.
90 #here we update the account lines
91 my ( $borrowernumber, $data ) = @_;
92 my $dbh = C4::Context->dbh;
95 my $branch = C4::Context->userenv->{'branch'};
96 my $amountleft = $data;
98 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
101 my $nextaccntno = getnextacctno($borrowernumber);
103 # get lines with outstanding amounts to offset
104 my $sth = $dbh->prepare(
105 "SELECT * FROM accountlines
106 WHERE (borrowernumber = ?) AND (amountoutstanding<>0)
109 $sth->execute($borrowernumber);
111 # offset transactions
113 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft > 0 ) ) {
114 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
116 $amountleft -= $accdata->{'amountoutstanding'};
119 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
122 my $thisacct = $accdata->{accountlines_id};
123 my $usth = $dbh->prepare(
124 "UPDATE accountlines SET amountoutstanding= ?
125 WHERE (accountlines_id = ?)"
127 $usth->execute( $newamtos, $thisacct );
129 if ( C4::Context->preference("FinesLog") ) {
130 $accdata->{'amountoutstanding_new'} = $newamtos;
131 logaction("FINES", 'MODIFY', $borrowernumber, Dumper({
132 action => 'fee_payment',
133 borrowernumber => $accdata->{'borrowernumber'},
134 old_amountoutstanding => $accdata->{'amountoutstanding'},
135 new_amountoutstanding => $newamtos,
136 amount_paid => $accdata->{'amountoutstanding'} - $newamtos,
137 accountlines_id => $accdata->{'accountlines_id'},
138 accountno => $accdata->{'accountno'},
139 manager_id => $manager_id,
141 push( @ids, $accdata->{'accountlines_id'} );
146 my $usth = $dbh->prepare(
147 "INSERT INTO accountlines
148 (borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding,manager_id)
149 VALUES (?,?,now(),?,'Payment,thanks','Pay',?,?)"
151 $usth->execute( $borrowernumber, $nextaccntno, 0 - $data, 0 - $amountleft, $manager_id );
153 UpdateStats( $branch, 'payment', $data, '', '', '', $borrowernumber, $nextaccntno );
155 if ( C4::Context->preference("FinesLog") ) {
156 $accdata->{'amountoutstanding_new'} = $newamtos;
157 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
158 action => 'create_payment',
159 borrowernumber => $borrowernumber,
160 accountno => $nextaccntno,
161 amount => $data * -1,
162 amountoutstanding => $amountleft * -1,
163 accounttype => 'Pay',
164 accountlines_paid => \@ids,
165 manager_id => $manager_id,
173 &makepayment($accountlines_id, $borrowernumber, $acctnumber, $amount, $branchcode);
175 Records the fact that a patron has paid off the entire amount he or
178 C<$borrowernumber> is the patron's borrower number. C<$acctnumber> is
179 the account that was credited. C<$amount> is the amount paid (this is
180 only used to record the payment. It is assumed to be equal to the
181 amount owed). C<$branchcode> is the code of the branch where payment
187 # FIXME - I'm not at all sure about the above, because I don't
188 # understand what the acct* tables in the Koha database are for.
191 #here we update both the accountoffsets and the account lines
192 #updated to check, if they are paying off a lost item, we return the item
193 # from their card, and put a note on the item record
194 my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_;
195 my $dbh = C4::Context->dbh;
197 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
200 my $nextaccntno = getnextacctno($borrowernumber);
202 my $sth = $dbh->prepare("SELECT * FROM accountlines WHERE accountlines_id=?");
203 $sth->execute( $accountlines_id );
204 my $data = $sth->fetchrow_hashref;
207 if ( $data->{'accounttype'} eq "Pay" ){
211 SET amountoutstanding = 0, description = 'Payment,thanks'
212 WHERE accountlines_id = ?
215 $udp->execute($accountlines_id);
220 SET amountoutstanding = 0
221 WHERE accountlines_id = ?
224 $udp->execute($accountlines_id);
227 my $payment = 0 - $amount;
228 $payment_note //= "";
233 INTO accountlines (borrowernumber, accountno, date, amount, itemnumber, description, accounttype, amountoutstanding, manager_id, note)
234 VALUES ( ?, ?, now(), ?, ?, 'Payment,thanks', 'Pay', 0, ?, ?)"
236 $ins->execute($borrowernumber, $nextaccntno, $payment, $data->{'itemnumber'}, $manager_id, $payment_note);
239 if ( C4::Context->preference("FinesLog") ) {
240 logaction("FINES", 'MODIFY', $borrowernumber, Dumper({
241 action => 'fee_payment',
242 borrowernumber => $borrowernumber,
243 old_amountoutstanding => $data->{'amountoutstanding'},
244 new_amountoutstanding => 0,
245 amount_paid => $data->{'amountoutstanding'},
246 accountlines_id => $data->{'accountlines_id'},
247 accountno => $data->{'accountno'},
248 manager_id => $manager_id,
252 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
253 action => 'create_payment',
254 borrowernumber => $borrowernumber,
255 accountno => $nextaccntno,
257 amountoutstanding => 0,,
258 accounttype => 'Pay',
259 accountlines_paid => [$data->{'accountlines_id'}],
260 manager_id => $manager_id,
265 # FIXME - The second argument to &UpdateStats is supposed to be the
267 # UpdateStats is now being passed $accountno too. MTJ
268 UpdateStats( $user, 'payment', $amount, '', '', '', $borrowernumber,
271 #check to see what accounttype
272 if ( $data->{'accounttype'} eq 'Rep' || $data->{'accounttype'} eq 'L' ) {
273 C4::Circulation::ReturnLostItem( $borrowernumber, $data->{'itemnumber'} );
275 my $sthr = $dbh->prepare("SELECT max(accountlines_id) AS lastinsertid FROM accountlines");
277 my $datalastinsertid = $sthr->fetchrow_hashref;
278 return $datalastinsertid->{'lastinsertid'};
283 $nextacct = &getnextacctno($borrowernumber);
285 Returns the next unused account number for the patron with the given
291 # FIXME - Okay, so what does the above actually _mean_?
293 my ($borrowernumber) = shift or return;
294 my $sth = C4::Context->dbh->prepare(
295 "SELECT accountno+1 FROM accountlines
296 WHERE (borrowernumber = ?)
297 ORDER BY accountno DESC
300 $sth->execute($borrowernumber);
301 return ($sth->fetchrow || 1);
304 =head2 fixaccounts (removed)
306 &fixaccounts($accountlines_id, $borrowernumber, $accountnumber, $amount);
309 # FIXME - I don't understand what this function does.
311 my ( $accountlines_id, $borrowernumber, $accountno, $amount ) = @_;
312 my $dbh = C4::Context->dbh;
313 my $sth = $dbh->prepare(
314 "SELECT * FROM accountlines WHERE accountlines_id=?"
316 $sth->execute( $accountlines_id );
317 my $data = $sth->fetchrow_hashref;
319 # FIXME - Error-checking
320 my $diff = $amount - $data->{'amount'};
321 my $outstanding = $data->{'amountoutstanding'} + $diff;
326 SET amount = '$amount',
327 amountoutstanding = '$outstanding'
328 WHERE accountlines_id = $accountlines_id
330 # FIXME: exceedingly bad form. Use prepare with placholders ("?") in query and execute args.
336 # lost ==1 Lost, lost==2 longoverdue, lost==3 lost and paid for
337 # FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that
338 # a charge has been added
339 # FIXME : if no replacement price, borrower just doesn't get charged?
340 my $dbh = C4::Context->dbh();
341 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
343 # first make sure the borrower hasn't already been charged for this item
344 my $sth1=$dbh->prepare("SELECT * from accountlines
345 WHERE borrowernumber=? AND itemnumber=? and accounttype='L'");
346 $sth1->execute($borrowernumber,$itemnumber);
347 my $existing_charge_hashref=$sth1->fetchrow_hashref();
350 unless ($existing_charge_hashref) {
352 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
353 # This item is on issue ... add replacement cost to the borrower's record and mark it returned
354 # Note that we add this to the account even if there's no replacement price, allowing some other
355 # process (or person) to update it, since we don't handle any defaults for replacement prices.
356 my $accountno = getnextacctno($borrowernumber);
357 my $sth2=$dbh->prepare("INSERT INTO accountlines
358 (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding,itemnumber,manager_id)
359 VALUES (?,?,now(),?,?,'L',?,?,?)");
360 $sth2->execute($borrowernumber,$accountno,$amount,
361 $description,$amount,$itemnumber,$manager_id);
363 if ( C4::Context->preference("FinesLog") ) {
364 logaction("FINES", 'CREATE', $borrowernumber, Dumper({
365 action => 'create_fee',
366 borrowernumber => $borrowernumber,
367 accountno => $accountno,
369 amountoutstanding => $amount,
370 description => $description,
372 itemnumber => $itemnumber,
373 manager_id => $manager_id,
382 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
385 C<$borrowernumber> is the patron's borrower number.
386 C<$description> is a description of the transaction.
387 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
389 C<$itemnumber> is the item involved, if pertinent; otherwise, it
390 should be the empty string.
395 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
398 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
401 # 'A' = Account Management fee
407 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
409 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
410 my $dbh = C4::Context->dbh;
413 my $accountno = getnextacctno($borrowernumber);
414 my $amountleft = $amount;
422 # my $amount2 = $amount * -1; # FIXME - $amount2 = -$amount
424 # fixcredit( $borrowernumber, $amount2, $itemnum, $type, $user );
426 if ( $type eq 'N' ) {
427 $desc .= " New Card";
429 if ( $type eq 'F' ) {
432 if ( $type eq 'A' ) {
433 $desc .= " Account Management fee";
435 if ( $type eq 'M' ) {
439 if ( $type eq 'L' && $desc eq '' ) {
441 $desc = " Lost Item";
443 # if ( $type eq 'REF' ) {
444 # $desc .= " Cash Refund";
445 # $amountleft = refund( '', $borrowernumber, $amount );
447 if ( ( $type eq 'L' )
451 or ( $type eq 'M' ) )
457 $desc .= ' ' . $itemnum;
458 my $sth = $dbh->prepare(
459 'INSERT INTO accountlines
460 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding, itemnumber,notify_id, note, manager_id)
461 VALUES (?, ?, now(), ?,?, ?,?,?,?,?,?)');
462 $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft, $itemnum,$notifyid, $note, $manager_id) || return $sth->errstr;
464 my $sth=$dbh->prepare("INSERT INTO accountlines
465 (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding,notify_id, note, manager_id)
466 VALUES (?, ?, now(), ?, ?, ?, ?,?,?,?)"
468 $sth->execute( $borrowernumber, $accountno, $amount, $desc, $type,
469 $amountleft, $notifyid, $note, $manager_id );
472 if ( C4::Context->preference("FinesLog") ) {
473 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
474 action => 'create_fee',
475 borrowernumber => $borrowernumber,
476 accountno => $accountno,
478 description => $desc,
479 accounttype => $type,
480 amountoutstanding => $amountleft,
481 notify_id => $notifyid,
483 itemnumber => $itemnum,
484 manager_id => $manager_id,
491 =head2 fixcredit #### DEPRECATED
493 $amountleft = &fixcredit($borrowernumber, $data, $barcode, $type, $user);
495 This function is only used internally, not exported.
499 # This function is deprecated in 3.0
503 #here we update both the accountoffsets and the account lines
504 my ( $borrowernumber, $data, $barcode, $type, $user ) = @_;
505 my $dbh = C4::Context->dbh;
508 my $amountleft = $data;
509 if ( $barcode ne '' ) {
510 my $item = GetBiblioFromItemNumber( '', $barcode );
511 my $nextaccntno = getnextacctno($borrowernumber);
512 my $query = "SELECT * FROM accountlines WHERE (borrowernumber=?
513 AND itemnumber=? AND amountoutstanding > 0)";
514 if ( $type eq 'CL' ) {
515 $query .= " AND (accounttype = 'L' OR accounttype = 'Rep')";
517 elsif ( $type eq 'CF' ) {
518 $query .= " AND (accounttype = 'F' OR accounttype = 'FU' OR
519 accounttype='Res' OR accounttype='Rent')";
521 elsif ( $type eq 'CB' ) {
522 $query .= " and accounttype='A'";
526 my $sth = $dbh->prepare($query);
527 $sth->execute( $borrowernumber, $item->{'itemnumber'} );
528 $accdata = $sth->fetchrow_hashref;
529 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
531 $amountleft -= $accdata->{'amountoutstanding'};
534 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
537 my $thisacct = $accdata->{accountlines_id};
538 my $usth = $dbh->prepare(
539 "UPDATE accountlines SET amountoutstanding= ?
540 WHERE (accountlines_id = ?)"
542 $usth->execute( $newamtos, $thisacct );
543 $usth = $dbh->prepare(
544 "INSERT INTO accountoffsets
545 (borrowernumber, accountno, offsetaccount, offsetamount)
548 $usth->execute( $borrowernumber, $accdata->{'accountno'},
549 $nextaccntno, $newamtos );
553 my $nextaccntno = getnextacctno($borrowernumber);
555 # get lines with outstanding amounts to offset
556 my $sth = $dbh->prepare(
557 "SELECT * FROM accountlines
558 WHERE (borrowernumber = ?) AND (amountoutstanding >0)
561 $sth->execute($borrowernumber);
564 # offset transactions
565 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft > 0 ) ) {
566 if ( $accdata->{'amountoutstanding'} < $amountleft ) {
568 $amountleft -= $accdata->{'amountoutstanding'};
571 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
574 my $thisacct = $accdata->{accountlines_id};
575 my $usth = $dbh->prepare(
576 "UPDATE accountlines SET amountoutstanding= ?
577 WHERE (accountlines_id = ?)"
579 $usth->execute( $newamtos, $thisacct );
580 $usth = $dbh->prepare(
581 "INSERT INTO accountoffsets
582 (borrowernumber, accountno, offsetaccount, offsetamount)
585 $usth->execute( $borrowernumber, $accdata->{'accountno'},
586 $nextaccntno, $newamtos );
588 $type = "Credit " . $type;
589 UpdateStats( $user, $type, $data, $user, '', '', $borrowernumber );
591 return ($amountleft);
597 #FIXME : DEPRECATED SUB
598 This subroutine tracks payments and/or credits against fines/charges
599 using the accountoffsets table, which is not used consistently in
600 Koha's fines management, and so is not used in 3.0
606 #here we update both the accountoffsets and the account lines
607 my ( $borrowernumber, $data ) = @_;
608 my $dbh = C4::Context->dbh;
611 my $amountleft = $data * -1;
614 my $nextaccntno = getnextacctno($borrowernumber);
616 # get lines with outstanding amounts to offset
617 my $sth = $dbh->prepare(
618 "SELECT * FROM accountlines
619 WHERE (borrowernumber = ?) AND (amountoutstanding<0)
622 $sth->execute($borrowernumber);
625 # offset transactions
626 while ( ( $accdata = $sth->fetchrow_hashref ) and ( $amountleft < 0 ) ) {
627 if ( $accdata->{'amountoutstanding'} > $amountleft ) {
629 $amountleft -= $accdata->{'amountoutstanding'};
632 $newamtos = $accdata->{'amountoutstanding'} - $amountleft;
637 my $thisacct = $accdata->{accountlines_id};
638 my $usth = $dbh->prepare(
639 "UPDATE accountlines SET amountoutstanding= ?
640 WHERE (accountlines_id = ?)"
642 $usth->execute( $newamtos, $thisacct );
643 $usth = $dbh->prepare(
644 "INSERT INTO accountoffsets
645 (borrowernumber, accountno, offsetaccount, offsetamount)
648 $usth->execute( $borrowernumber, $accdata->{'accountno'},
649 $nextaccntno, $newamtos );
651 return ($amountleft);
655 my ( $borrowerno, $timestamp, $accountno ) = @_;
656 my $dbh = C4::Context->dbh;
657 my $timestamp2 = $timestamp - 1;
659 my $sth = $dbh->prepare(
660 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
662 $sth->execute( $borrowerno, $accountno );
665 while ( my $data = $sth->fetchrow_hashref ) {
672 my ( $accountlines_id, $note ) = @_;
673 my $dbh = C4::Context->dbh;
674 my $sth = $dbh->prepare('UPDATE accountlines SET note = ? WHERE accountlines_id = ?');
675 $sth->execute( $note, $accountlines_id );
679 my ( $date, $date2 ) = @_;
680 my $dbh = C4::Context->dbh;
681 my $sth = $dbh->prepare(
682 "SELECT * FROM accountlines,borrowers
683 WHERE amount < 0 AND accounttype <> 'Pay' AND accountlines.borrowernumber = borrowers.borrowernumber
684 AND timestamp >=TIMESTAMP(?) AND timestamp < TIMESTAMP(?)"
687 $sth->execute( $date, $date2 );
689 while ( my $data = $sth->fetchrow_hashref ) {
690 $data->{'date'} = $data->{'timestamp'};
698 my ( $date, $date2 ) = @_;
699 my $dbh = C4::Context->dbh;
701 my $sth = $dbh->prepare(
702 "SELECT *,timestamp AS datetime
703 FROM accountlines,borrowers
704 WHERE (accounttype = 'REF'
705 AND accountlines.borrowernumber = borrowers.borrowernumber
706 AND date >=? AND date <?)"
709 $sth->execute( $date, $date2 );
712 while ( my $data = $sth->fetchrow_hashref ) {
720 my ( $accountlines_id ) = @_;
721 my $dbh = C4::Context->dbh;
723 my $sth = $dbh->prepare('SELECT * FROM accountlines WHERE accountlines_id = ?');
724 $sth->execute( $accountlines_id );
725 my $row = $sth->fetchrow_hashref();
726 my $amount_outstanding = $row->{'amountoutstanding'};
728 if ( $amount_outstanding <= 0 ) {
729 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = amount * -1, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?');
730 $sth->execute( $accountlines_id );
732 $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = 0, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?');
733 $sth->execute( $accountlines_id );
736 if ( C4::Context->preference("FinesLog") ) {
738 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
740 if ( $amount_outstanding <= 0 ) {
741 $row->{'amountoutstanding'} *= -1;
743 $row->{'amountoutstanding'} = '0';
745 $row->{'description'} .= ' Reversed -';
746 logaction("FINES", 'MODIFY', $row->{'borrowernumber'}, Dumper({
747 action => 'reverse_fee_payment',
748 borrowernumber => $row->{'borrowernumber'},
749 old_amountoutstanding => $row->{'amountoutstanding'},
750 new_amountoutstanding => 0 - $amount_outstanding,,
751 accountlines_id => $row->{'accountlines_id'},
752 accountno => $row->{'accountno'},
753 manager_id => $manager_id,
760 =head2 recordpayment_selectaccts
762 recordpayment_selectaccts($borrowernumber, $payment,$accts);
764 Record payment by a patron. C<$borrowernumber> is the patron's
765 borrower number. C<$payment> is a floating-point number, giving the
766 amount that was paid. C<$accts> is an array ref to a list of
767 accountnos which the payment can be recorded against
769 Amounts owed are paid off oldest first. That is, if the patron has a
770 $1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment
771 of $1.50, then the oldest fine will be paid off in full, and $0.50
772 will be credited to the next one.
776 sub recordpayment_selectaccts {
777 my ( $borrowernumber, $amount, $accts, $note ) = @_;
779 my $dbh = C4::Context->dbh;
782 my $branch = C4::Context->userenv->{branch};
783 my $amountleft = $amount;
785 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
786 my $sql = 'SELECT * FROM accountlines WHERE (borrowernumber = ?) ' .
787 'AND (amountoutstanding<>0) ';
789 $sql .= ' AND accountno IN ( ' . join ',', @{$accts};
792 $sql .= ' ORDER BY date';
794 my $nextaccntno = getnextacctno($borrowernumber);
796 # get lines with outstanding amounts to offset
797 my $rows = $dbh->selectall_arrayref($sql, { Slice => {} }, $borrowernumber);
799 # offset transactions
800 my $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding= ? ' .
801 'WHERE accountlines_id=?');
804 for my $accdata ( @{$rows} ) {
805 if ($amountleft == 0) {
808 if ( $accdata->{amountoutstanding} < $amountleft ) {
810 $amountleft -= $accdata->{amountoutstanding};
813 $newamtos = $accdata->{amountoutstanding} - $amountleft;
816 my $thisacct = $accdata->{accountlines_id};
817 $sth->execute( $newamtos, $thisacct );
819 if ( C4::Context->preference("FinesLog") ) {
820 logaction("FINES", 'MODIFY', $borrowernumber, Dumper({
821 action => 'fee_payment',
822 borrowernumber => $borrowernumber,
823 old_amountoutstanding => $accdata->{'amountoutstanding'},
824 new_amountoutstanding => $newamtos,
825 amount_paid => $accdata->{'amountoutstanding'} - $newamtos,
826 accountlines_id => $accdata->{'accountlines_id'},
827 accountno => $accdata->{'accountno'},
828 manager_id => $manager_id,
830 push( @ids, $accdata->{'accountlines_id'} );
836 $sql = 'INSERT INTO accountlines ' .
837 '(borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding,manager_id,note) ' .
838 q|VALUES (?,?,now(),?,'Payment,thanks','Pay',?,?,?)|;
839 $dbh->do($sql,{},$borrowernumber, $nextaccntno, 0 - $amount, 0 - $amountleft, $manager_id, $note );
840 UpdateStats( $branch, 'payment', $amount, '', '', '', $borrowernumber, $nextaccntno );
842 if ( C4::Context->preference("FinesLog") ) {
843 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
844 action => 'create_payment',
845 borrowernumber => $borrowernumber,
846 accountno => $nextaccntno,
847 amount => 0 - $amount,
848 amountoutstanding => 0 - $amountleft,
849 accounttype => 'Pay',
850 accountlines_paid => \@ids,
851 manager_id => $manager_id,
858 # makepayment needs to be fixed to handle partials till then this separate subroutine
860 sub makepartialpayment {
861 my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_;
863 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
864 if (!$amount || $amount < 0) {
867 $payment_note //= "";
868 my $dbh = C4::Context->dbh;
870 my $nextaccntno = getnextacctno($borrowernumber);
873 my $data = $dbh->selectrow_hashref(
874 'SELECT * FROM accountlines WHERE accountlines_id=?',undef,$accountlines_id);
875 my $new_outstanding = $data->{amountoutstanding} - $amount;
877 my $update = 'UPDATE accountlines SET amountoutstanding = ? WHERE accountlines_id = ? ';
878 $dbh->do( $update, undef, $new_outstanding, $accountlines_id);
880 if ( C4::Context->preference("FinesLog") ) {
881 logaction("FINES", 'MODIFY', $borrowernumber, Dumper({
882 action => 'fee_payment',
883 borrowernumber => $borrowernumber,
884 old_amountoutstanding => $data->{'amountoutstanding'},
885 new_amountoutstanding => $new_outstanding,
886 amount_paid => $data->{'amountoutstanding'} - $new_outstanding,
887 accountlines_id => $data->{'accountlines_id'},
888 accountno => $data->{'accountno'},
889 manager_id => $manager_id,
894 my $insert = 'INSERT INTO accountlines (borrowernumber, accountno, date, amount, '
895 . 'description, accounttype, amountoutstanding, itemnumber, manager_id, note) '
896 . ' VALUES (?, ?, now(), ?, ?, ?, 0, ?, ?, ?)';
898 $dbh->do( $insert, undef, $borrowernumber, $nextaccntno, $amount,
899 "Payment, thanks - $user", 'Pay', $data->{'itemnumber'}, $manager_id, $payment_note);
901 UpdateStats( $user, 'payment', $amount, '', '', '', $borrowernumber, $accountno );
903 if ( C4::Context->preference("FinesLog") ) {
904 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
905 action => 'create_payment',
906 borrowernumber => $user,
907 accountno => $nextaccntno,
908 amount => 0 - $amount,
909 accounttype => 'Pay',
910 itemnumber => $data->{'itemnumber'},
911 accountlines_paid => [ $data->{'accountlines_id'} ],
912 manager_id => $manager_id,
921 WriteOffFee( $borrowernumber, $accountline_id, $itemnum, $accounttype, $amount, $branch, $payment_note );
923 Write off a fine for a patron.
924 C<$borrowernumber> is the patron's borrower number.
925 C<$accountline_id> is the accountline_id of the fee to write off.
926 C<$itemnum> is the itemnumber of of item whose fine is being written off.
927 C<$accounttype> is the account type of the fine being written off.
928 C<$amount> is a floating-point number, giving the amount that is being written off.
929 C<$branch> is the branchcode of the library where the writeoff occurred.
930 C<$payment_note> is the note to attach to this payment
935 my ( $borrowernumber, $accountlines_id, $itemnum, $accounttype, $amount, $branch, $payment_note ) = @_;
936 $payment_note //= "";
937 $branch ||= C4::Context->userenv->{branch};
939 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
941 # if no item is attached to fine, make sure to store it as a NULL
945 my $dbh = C4::Context->dbh();
948 UPDATE accountlines SET amountoutstanding = 0
949 WHERE accountlines_id = ? AND borrowernumber = ?
951 $sth = $dbh->prepare( $query );
952 $sth->execute( $accountlines_id, $borrowernumber );
954 if ( C4::Context->preference("FinesLog") ) {
955 logaction("FINES", 'MODIFY', $borrowernumber, Dumper({
956 action => 'fee_writeoff',
957 borrowernumber => $borrowernumber,
958 accountlines_id => $accountlines_id,
959 manager_id => $manager_id,
964 INSERT INTO accountlines
965 ( borrowernumber, accountno, itemnumber, date, amount, description, accounttype, manager_id, note )
966 VALUES ( ?, ?, ?, NOW(), ?, 'Writeoff', 'W', ?, ? )
968 $sth = $dbh->prepare( $query );
969 my $acct = getnextacctno($borrowernumber);
970 $sth->execute( $borrowernumber, $acct, $itemnum, $amount, $manager_id, $payment_note );
972 if ( C4::Context->preference("FinesLog") ) {
973 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
974 action => 'create_writeoff',
975 borrowernumber => $borrowernumber,
977 amount => 0 - $amount,
979 itemnumber => $itemnum,
980 accountlines_paid => [ $accountlines_id ],
981 manager_id => $manager_id,
985 UpdateStats( $branch, 'writeoff', $amount, q{}, q{}, q{}, $borrowernumber );
989 END { } # module clean-up code here (global destructor)