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 Koha::Account::Lines;
30 use Koha::Account::Offsets;
33 use Data::Dumper qw(Dumper);
35 use vars qw(@ISA @EXPORT);
49 &purge_zero_balance_fees
55 C4::Accounts - Functions for dealing with Koha accounts
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
71 $nextacct = &getnextacctno($borrowernumber);
73 Returns the next unused account number for the patron with the given
79 # FIXME - Okay, so what does the above actually _mean_?
81 my ($borrowernumber) = shift or return;
82 my $sth = C4::Context->dbh->prepare(
83 "SELECT accountno+1 FROM accountlines
84 WHERE (borrowernumber = ?)
85 ORDER BY accountno DESC
88 $sth->execute($borrowernumber);
89 return ($sth->fetchrow || 1);
92 =head2 fixaccounts (removed)
94 &fixaccounts($accountlines_id, $borrowernumber, $accountnumber, $amount);
97 # FIXME - I don't understand what this function does.
99 my ( $accountlines_id, $borrowernumber, $accountno, $amount ) = @_;
100 my $dbh = C4::Context->dbh;
101 my $sth = $dbh->prepare(
102 "SELECT * FROM accountlines WHERE accountlines_id=?"
104 $sth->execute( $accountlines_id );
105 my $data = $sth->fetchrow_hashref;
107 # FIXME - Error-checking
108 my $diff = $amount - $data->{'amount'};
109 my $outstanding = $data->{'amountoutstanding'} + $diff;
114 SET amount = '$amount',
115 amountoutstanding = '$outstanding'
116 WHERE accountlines_id = $accountlines_id
118 # FIXME: exceedingly bad form. Use prepare with placholders ("?") in query and execute args.
123 =head2 chargelostitem
125 In a default install of Koha the following lost values are set
128 3 = Lost and paid for
130 FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that a charge has been added
131 FIXME : if no replacement price, borrower just doesn't get charged?
136 my $dbh = C4::Context->dbh();
137 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
138 my $itype = Koha::ItemTypes->find({ itemtype => Koha::Items->find($itemnumber)->effective_itemtype() });
139 my $replacementprice = $amount;
140 my $defaultreplacecost = $itype->defaultreplacecost;
141 my $processfee = $itype->processfee;
142 my $usedefaultreplacementcost = C4::Context->preference("useDefaultReplacementCost");
143 my $processingfeenote = C4::Context->preference("ProcessingFeeNote");
144 if ($usedefaultreplacementcost && $amount == 0 && $defaultreplacecost){
145 $replacementprice = $defaultreplacecost;
147 # first make sure the borrower hasn't already been charged for this item
148 # FIXME this should be more exact
149 # there is no reason a user can't lose an item, find and return it, and lost it again
150 my $existing_charges = Koha::Account::Lines->search(
152 borrowernumber => $borrowernumber,
153 itemnumber => $itemnumber,
159 unless ($existing_charges) {
161 if ($processfee && $processfee > 0){
162 manualinvoice($borrowernumber, $itemnumber, $description, 'PF', $processfee, $processingfeenote, 1);
165 if ($replacementprice > 0){
166 manualinvoice($borrowernumber, $itemnumber, $description, 'L', $replacementprice, undef, 1);
173 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
176 C<$borrowernumber> is the patron's borrower number.
177 C<$description> is a description of the transaction.
178 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
180 C<$itemnumber> is the item involved, if pertinent; otherwise, it
181 should be the empty string.
186 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
189 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
192 # 'A' = Account Management fee
198 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note, $skip_notify ) = @_;
200 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
201 my $dbh = C4::Context->dbh;
204 my $accountno = getnextacctno($borrowernumber);
205 my $amountleft = $amount;
208 if ( ( $type eq 'L' )
212 or ( $type eq 'M' ) )
214 $notifyid = 1 unless $skip_notify;
217 my $accountline = Koha::Account::Line->new(
219 borrowernumber => $borrowernumber,
220 accountno => $accountno,
223 description => $desc,
224 accounttype => $type,
225 amountoutstanding => $amountleft,
226 itemnumber => $itemnum || undef,
227 notify_id => $notifyid,
229 manager_id => $manager_id,
233 my $account_offset = Koha::Account::Offset->new(
235 debit_id => $accountline->id,
236 type => 'Manual Debit',
241 if ( C4::Context->preference("FinesLog") ) {
242 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
243 action => 'create_fee',
244 borrowernumber => $borrowernumber,
245 accountno => $accountno,
247 description => $desc,
248 accounttype => $type,
249 amountoutstanding => $amountleft,
250 notify_id => $notifyid,
252 itemnumber => $itemnum,
253 manager_id => $manager_id,
261 my ( $borrowerno, $timestamp, $accountno ) = @_;
262 my $dbh = C4::Context->dbh;
263 my $timestamp2 = $timestamp - 1;
265 my $sth = $dbh->prepare(
266 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
268 $sth->execute( $borrowerno, $accountno );
271 while ( my $data = $sth->fetchrow_hashref ) {
278 my ( $accountlines_id, $note ) = @_;
279 my $dbh = C4::Context->dbh;
280 my $sth = $dbh->prepare('UPDATE accountlines SET note = ? WHERE accountlines_id = ?');
281 $sth->execute( $note, $accountlines_id );
285 my ( $date, $date2 ) = @_;
286 my $dbh = C4::Context->dbh;
287 my $sth = $dbh->prepare(
288 "SELECT * FROM accountlines,borrowers
289 WHERE amount < 0 AND accounttype not like 'Pay%' AND accountlines.borrowernumber = borrowers.borrowernumber
290 AND timestamp >=TIMESTAMP(?) AND timestamp < TIMESTAMP(?)"
293 $sth->execute( $date, $date2 );
295 while ( my $data = $sth->fetchrow_hashref ) {
296 $data->{'date'} = $data->{'timestamp'};
304 my ( $date, $date2 ) = @_;
305 my $dbh = C4::Context->dbh;
307 my $sth = $dbh->prepare(
308 "SELECT *,timestamp AS datetime
309 FROM accountlines,borrowers
310 WHERE (accounttype = 'REF'
311 AND accountlines.borrowernumber = borrowers.borrowernumber
312 AND date >=? AND date <?)"
315 $sth->execute( $date, $date2 );
318 while ( my $data = $sth->fetchrow_hashref ) {
325 #FIXME: ReversePayment should be replaced with a Void Payment feature
327 my ($accountlines_id) = @_;
328 my $dbh = C4::Context->dbh;
330 my $accountline = Koha::Account::Lines->find($accountlines_id);
331 my $amount_outstanding = $accountline->amountoutstanding;
333 my $new_amountoutstanding =
334 $amount_outstanding <= 0 ? $accountline->amount * -1 : 0;
336 $accountline->description( $accountline->description . " Reversed -" );
337 $accountline->amountoutstanding($new_amountoutstanding);
338 $accountline->store();
340 my $account_offset = Koha::Account::Offset->new(
342 credit_id => $accountline->id,
343 type => 'Reverse Payment',
344 amount => $amount_outstanding - $new_amountoutstanding,
348 if ( C4::Context->preference("FinesLog") ) {
350 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
354 $accountline->borrowernumber,
357 action => 'reverse_fee_payment',
358 borrowernumber => $accountline->borrowernumber,
359 old_amountoutstanding => $amount_outstanding,
360 new_amountoutstanding => $new_amountoutstanding,
362 accountlines_id => $accountline->id,
363 accountno => $accountline->accountno,
364 manager_id => $manager_id,
371 =head2 purge_zero_balance_fees
373 purge_zero_balance_fees( $days );
375 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
377 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
379 B<Warning:> Because fines and payments are not linked in accountlines, it is
380 possible for a fine to be deleted without the accompanying payment,
381 or vise versa. This won't affect the account balance, but might be
386 sub purge_zero_balance_fees {
390 my $dbh = C4::Context->dbh;
391 my $sth = $dbh->prepare(
393 DELETE FROM accountlines
394 WHERE date < date_sub(curdate(), INTERVAL ? DAY)
395 AND ( amountoutstanding = 0 or amountoutstanding IS NULL );
398 $sth->execute($days) or die $dbh->errstr;
401 END { } # module clean-up code here (global destructor)