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 my $accountline = Koha
::Account
::Line
->new(
164 borrowernumber
=> $borrowernumber,
165 accountno
=> getnextacctno
($borrowernumber),
167 amount => $processfee,
168 description => $description,
170 amountoutstanding => $processfee,
171 itemnumber => $itemnumber,
172 note => $processingfeenote,
173 manager_id => C4::Context->userenv ? C4::Context->userenv->{'number
'} : 0,
177 my $account_offset = Koha::Account::Offset->new(
179 debit_id => $accountline->id,
180 type => 'Processing Fee
',
181 amount => $accountline->amount,
185 if ( C4::Context->preference("FinesLog") ) {
186 logaction("FINES", 'CREATE
',$borrowernumber,Dumper({
187 action => 'create_fee
',
188 borrowernumber => $accountline->borrowernumber,,
189 accountno => $accountline->accountno,
190 amount => $accountline->amount,
191 description => $accountline->description,
192 accounttype => $accountline->accounttype,
193 amountoutstanding => $accountline->amountoutstanding,
194 note => $accountline->note,
195 itemnumber => $accountline->itemnumber,
196 manager_id => $accountline->manager_id,
201 if ($replacementprice > 0){
202 my $accountline = Koha::Account::Line->new(
204 borrowernumber => $borrowernumber,
205 accountno => getnextacctno($borrowernumber),
207 amount
=> $replacementprice,
208 description
=> $description,
210 amountoutstanding
=> $replacementprice,
211 itemnumber
=> $itemnumber,
212 manager_id
=> C4
::Context
->userenv ? C4
::Context
->userenv->{'number'} : 0,
216 my $account_offset = Koha
::Account
::Offset
->new(
218 debit_id
=> $accountline->id,
220 amount
=> $accountline->amount,
224 if ( C4
::Context
->preference("FinesLog") ) {
225 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
226 action
=> 'create_fee',
227 borrowernumber
=> $accountline->borrowernumber,,
228 accountno
=> $accountline->accountno,
229 amount
=> $accountline->amount,
230 description
=> $accountline->description,
231 accounttype
=> $accountline->accounttype,
232 amountoutstanding
=> $accountline->amountoutstanding,
233 note
=> $accountline->note,
234 itemnumber
=> $accountline->itemnumber,
235 manager_id
=> $accountline->manager_id,
244 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
247 C<$borrowernumber> is the patron's borrower number.
248 C<$description> is a description of the transaction.
249 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
251 C<$itemnumber> is the item involved, if pertinent; otherwise, it
252 should be the empty string.
257 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
260 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
263 # 'A' = Account Management fee
269 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
271 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
272 my $dbh = C4
::Context
->dbh;
274 my $accountno = getnextacctno
($borrowernumber);
275 my $amountleft = $amount;
277 my $accountline = Koha
::Account
::Line
->new(
279 borrowernumber
=> $borrowernumber,
280 accountno
=> $accountno,
283 description => $desc,
284 accounttype => $type,
285 amountoutstanding => $amountleft,
286 itemnumber => $itemnum || undef,
288 manager_id => $manager_id,
292 my $account_offset = Koha::Account::Offset->new(
294 debit_id => $accountline->id,
295 type => 'Manual Debit
',
300 if ( C4::Context->preference("FinesLog") ) {
301 logaction("FINES", 'CREATE
',$borrowernumber,Dumper({
302 action => 'create_fee
',
303 borrowernumber => $borrowernumber,
304 accountno => $accountno,
306 description => $desc,
307 accounttype => $type,
308 amountoutstanding => $amountleft,
310 itemnumber => $itemnum,
311 manager_id => $manager_id,
319 my ( $borrowerno, $timestamp, $accountno ) = @_;
320 my $dbh = C4::Context->dbh;
321 my $timestamp2 = $timestamp - 1;
323 my $sth = $dbh->prepare(
324 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
326 $sth->execute( $borrowerno, $accountno );
329 while ( my $data = $sth->fetchrow_hashref ) {
336 my ( $accountlines_id, $note ) = @_;
337 my $dbh = C4::Context->dbh;
338 my $sth = $dbh->prepare('UPDATE accountlines SET note
= ? WHERE accountlines_id
= ?
');
339 $sth->execute( $note, $accountlines_id );
343 my ( $date, $date2 ) = @_;
344 my $dbh = C4::Context->dbh;
345 my $sth = $dbh->prepare(
346 "SELECT * FROM accountlines,borrowers
347 WHERE amount < 0 AND accounttype not like 'Pay
%' AND accountlines.borrowernumber = borrowers.borrowernumber
348 AND timestamp >=TIMESTAMP(?) AND timestamp < TIMESTAMP(?)"
351 $sth->execute( $date, $date2 );
353 while ( my $data = $sth->fetchrow_hashref ) {
354 $data->{'date
'} = $data->{'timestamp
'};
362 my ( $date, $date2 ) = @_;
363 my $dbh = C4::Context->dbh;
365 my $sth = $dbh->prepare(
366 "SELECT *,timestamp AS datetime
367 FROM accountlines,borrowers
368 WHERE (accounttype = 'REF
'
369 AND accountlines.borrowernumber = borrowers.borrowernumber
370 AND date >=? AND date <?)"
373 $sth->execute( $date, $date2 );
376 while ( my $data = $sth->fetchrow_hashref ) {
383 #FIXME: ReversePayment should be replaced with a Void Payment feature
385 my ($accountlines_id) = @_;
386 my $dbh = C4::Context->dbh;
388 my $accountline = Koha::Account::Lines->find($accountlines_id);
389 my $amount_outstanding = $accountline->amountoutstanding;
391 my $new_amountoutstanding =
392 $amount_outstanding <= 0 ? $accountline->amount * -1 : 0;
394 $accountline->description( $accountline->description . " Reversed -" );
395 $accountline->amountoutstanding($new_amountoutstanding);
396 $accountline->store();
398 my $account_offset = Koha::Account::Offset->new(
400 credit_id => $accountline->id,
401 type => 'Reverse Payment
',
402 amount => $amount_outstanding - $new_amountoutstanding,
406 if ( C4::Context->preference("FinesLog") ) {
408 $manager_id = C4::Context->userenv->{'number
'} if C4::Context->userenv;
412 $accountline->borrowernumber,
415 action => 'reverse_fee_payment
',
416 borrowernumber => $accountline->borrowernumber,
417 old_amountoutstanding => $amount_outstanding,
418 new_amountoutstanding => $new_amountoutstanding,
420 accountlines_id => $accountline->id,
421 accountno => $accountline->accountno,
422 manager_id => $manager_id,
429 =head2 purge_zero_balance_fees
431 purge_zero_balance_fees( $days );
433 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
435 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
437 B<Warning:> Because fines and payments are not linked in accountlines, it is
438 possible for a fine to be deleted without the accompanying payment,
439 or vise versa. This won't affect the account balance
, but might be
444 sub purge_zero_balance_fees
{
448 my $dbh = C4
::Context
->dbh;
449 my $sth = $dbh->prepare(
451 DELETE a1 FROM accountlines a1
453 LEFT JOIN account_offsets credit_offset ON ( a1.accountlines_id = credit_offset.credit_id )
454 LEFT JOIN accountlines a2 ON ( credit_offset.debit_id = a2.accountlines_id )
456 LEFT JOIN account_offsets debit_offset ON ( a1.accountlines_id = debit_offset.debit_id )
457 LEFT JOIN accountlines a3 ON ( debit_offset.credit_id = a3.accountlines_id )
459 WHERE a1.date < date_sub(curdate(), INTERVAL ? DAY)
460 AND ( a1.amountoutstanding = 0 OR a1.amountoutstanding IS NULL )
461 AND ( a2.amountoutstanding = 0 OR a2.amountoutstanding IS NULL )
462 AND ( a3.amountoutstanding = 0 OR a3.amountoutstanding IS NULL )
465 $sth->execute($days) or die $dbh->errstr;
468 END { } # module clean-up code here (global destructor)