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
::Log
qw(logaction);
28 use Koha
::Account
::Lines
;
29 use Koha
::Account
::Offsets
;
32 use Data
::Dumper
qw(Dumper);
34 use vars
qw(@ISA @EXPORT);
45 &purge_zero_balance_fees
51 C4::Accounts - Functions for dealing with Koha accounts
59 The functions in this module deal with the monetary aspect of Koha,
60 including looking up and modifying the amount of money owed by a
67 $nextacct = &getnextacctno($borrowernumber);
69 Returns the next unused account number for the patron with the given
75 # FIXME - Okay, so what does the above actually _mean_?
77 my ($borrowernumber) = shift or return;
78 my $sth = C4
::Context
->dbh->prepare(
79 "SELECT accountno+1 FROM accountlines
80 WHERE (borrowernumber = ?)
81 ORDER BY accountno DESC
84 $sth->execute($borrowernumber);
85 return ($sth->fetchrow || 1);
88 =head2 fixaccounts (removed)
90 &fixaccounts($accountlines_id, $borrowernumber, $accountnumber, $amount);
93 # FIXME - I don't understand what this function does.
95 my ( $accountlines_id, $borrowernumber, $accountno, $amount ) = @_;
96 my $dbh = C4::Context->dbh;
97 my $sth = $dbh->prepare(
98 "SELECT * FROM accountlines WHERE accountlines_id=?"
100 $sth->execute( $accountlines_id );
101 my $data = $sth->fetchrow_hashref;
103 # FIXME - Error-checking
104 my $diff = $amount - $data->{'amount'};
105 my $outstanding = $data->{'amountoutstanding'} + $diff;
110 SET amount = '$amount',
111 amountoutstanding = '$outstanding'
112 WHERE accountlines_id = $accountlines_id
114 # FIXME: exceedingly bad form. Use prepare with placholders ("?") in query and execute args.
119 =head2 chargelostitem
121 In a default install of Koha the following lost values are set
124 3 = Lost and paid for
126 FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that a charge has been added
127 FIXME : if no replacement price, borrower just doesn't get charged?
132 my $dbh = C4
::Context
->dbh();
133 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
134 my $itype = Koha
::ItemTypes
->find({ itemtype
=> Koha
::Items
->find($itemnumber)->effective_itemtype() });
135 my $replacementprice = $amount;
136 my $defaultreplacecost = $itype->defaultreplacecost;
137 my $processfee = $itype->processfee;
138 my $usedefaultreplacementcost = C4
::Context
->preference("useDefaultReplacementCost");
139 my $processingfeenote = C4
::Context
->preference("ProcessingFeeNote");
140 if ($usedefaultreplacementcost && $amount == 0 && $defaultreplacecost){
141 $replacementprice = $defaultreplacecost;
143 # first make sure the borrower hasn't already been charged for this item
144 # FIXME this should be more exact
145 # there is no reason a user can't lose an item, find and return it, and lost it again
146 my $existing_charges = Koha
::Account
::Lines
->search(
148 borrowernumber
=> $borrowernumber,
149 itemnumber
=> $itemnumber,
155 unless ($existing_charges) {
157 if ($processfee && $processfee > 0){
158 my $accountline = Koha
::Account
::Line
->new(
160 borrowernumber
=> $borrowernumber,
161 accountno
=> getnextacctno
($borrowernumber),
163 amount => $processfee,
164 description => $description,
166 amountoutstanding => $processfee,
167 itemnumber => $itemnumber,
168 note => $processingfeenote,
169 manager_id => C4::Context->userenv ? C4::Context->userenv->{'number
'} : 0,
173 my $account_offset = Koha::Account::Offset->new(
175 debit_id => $accountline->id,
176 type => 'Processing Fee
',
177 amount => $accountline->amount,
181 if ( C4::Context->preference("FinesLog") ) {
182 logaction("FINES", 'CREATE
',$borrowernumber,Dumper({
183 action => 'create_fee
',
184 borrowernumber => $accountline->borrowernumber,,
185 accountno => $accountline->accountno,
186 amount => $accountline->amount,
187 description => $accountline->description,
188 accounttype => $accountline->accounttype,
189 amountoutstanding => $accountline->amountoutstanding,
190 note => $accountline->note,
191 itemnumber => $accountline->itemnumber,
192 manager_id => $accountline->manager_id,
197 if ($replacementprice > 0){
198 my $accountline = Koha::Account::Line->new(
200 borrowernumber => $borrowernumber,
201 accountno => getnextacctno($borrowernumber),
203 amount
=> $replacementprice,
204 description
=> $description,
206 amountoutstanding
=> $replacementprice,
207 itemnumber
=> $itemnumber,
208 manager_id
=> C4
::Context
->userenv ? C4
::Context
->userenv->{'number'} : 0,
212 my $account_offset = Koha
::Account
::Offset
->new(
214 debit_id
=> $accountline->id,
216 amount
=> $accountline->amount,
220 if ( C4
::Context
->preference("FinesLog") ) {
221 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
222 action
=> 'create_fee',
223 borrowernumber
=> $accountline->borrowernumber,,
224 accountno
=> $accountline->accountno,
225 amount
=> $accountline->amount,
226 description
=> $accountline->description,
227 accounttype
=> $accountline->accounttype,
228 amountoutstanding
=> $accountline->amountoutstanding,
229 note
=> $accountline->note,
230 itemnumber
=> $accountline->itemnumber,
231 manager_id
=> $accountline->manager_id,
240 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
243 C<$borrowernumber> is the patron's borrower number.
244 C<$description> is a description of the transaction.
245 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
247 C<$itemnumber> is the item involved, if pertinent; otherwise, it
248 should be the empty string.
253 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
256 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
259 # 'A' = Account Management fee
265 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
267 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
268 my $dbh = C4
::Context
->dbh;
270 my $accountno = getnextacctno
($borrowernumber);
271 my $amountleft = $amount;
273 my $accountline = Koha
::Account
::Line
->new(
275 borrowernumber
=> $borrowernumber,
276 accountno
=> $accountno,
279 description => $desc,
280 accounttype => $type,
281 amountoutstanding => $amountleft,
282 itemnumber => $itemnum || undef,
284 manager_id => $manager_id,
288 my $account_offset = Koha::Account::Offset->new(
290 debit_id => $accountline->id,
291 type => 'Manual Debit
',
296 if ( C4::Context->preference("FinesLog") ) {
297 logaction("FINES", 'CREATE
',$borrowernumber,Dumper({
298 action => 'create_fee
',
299 borrowernumber => $borrowernumber,
300 accountno => $accountno,
302 description => $desc,
303 accounttype => $type,
304 amountoutstanding => $amountleft,
306 itemnumber => $itemnum,
307 manager_id => $manager_id,
315 my ( $borrowerno, $timestamp, $accountno ) = @_;
316 my $dbh = C4::Context->dbh;
317 my $timestamp2 = $timestamp - 1;
319 my $sth = $dbh->prepare(
320 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
322 $sth->execute( $borrowerno, $accountno );
325 while ( my $data = $sth->fetchrow_hashref ) {
331 #FIXME: ReversePayment should be replaced with a Void Payment feature
333 my ($accountlines_id) = @_;
334 my $dbh = C4::Context->dbh;
336 my $accountline = Koha::Account::Lines->find($accountlines_id);
337 my $amount_outstanding = $accountline->amountoutstanding;
339 my $new_amountoutstanding =
340 $amount_outstanding <= 0 ? $accountline->amount * -1 : 0;
342 $accountline->description( $accountline->description . " Reversed -" );
343 $accountline->amountoutstanding($new_amountoutstanding);
344 $accountline->store();
346 my $account_offset = Koha::Account::Offset->new(
348 credit_id => $accountline->id,
349 type => 'Reverse Payment
',
350 amount => $amount_outstanding - $new_amountoutstanding,
354 if ( C4::Context->preference("FinesLog") ) {
356 $manager_id = C4::Context->userenv->{'number
'} if C4::Context->userenv;
360 $accountline->borrowernumber,
363 action => 'reverse_fee_payment
',
364 borrowernumber => $accountline->borrowernumber,
365 old_amountoutstanding => $amount_outstanding,
366 new_amountoutstanding => $new_amountoutstanding,
368 accountlines_id => $accountline->id,
369 accountno => $accountline->accountno,
370 manager_id => $manager_id,
377 =head2 purge_zero_balance_fees
379 purge_zero_balance_fees( $days );
381 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
383 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
385 B<Warning:> Because fines and payments are not linked in accountlines, it is
386 possible for a fine to be deleted without the accompanying payment,
387 or vise versa. This won't affect the account balance
, but might be
392 sub purge_zero_balance_fees
{
396 my $dbh = C4
::Context
->dbh;
397 my $sth = $dbh->prepare(
399 DELETE a1 FROM accountlines a1
401 LEFT JOIN account_offsets credit_offset ON ( a1.accountlines_id = credit_offset.credit_id )
402 LEFT JOIN accountlines a2 ON ( credit_offset.debit_id = a2.accountlines_id )
404 LEFT JOIN account_offsets debit_offset ON ( a1.accountlines_id = debit_offset.debit_id )
405 LEFT JOIN accountlines a3 ON ( debit_offset.credit_id = a3.accountlines_id )
407 WHERE a1.date < date_sub(curdate(), INTERVAL ? DAY)
408 AND ( a1.amountoutstanding = 0 OR a1.amountoutstanding IS NULL )
409 AND ( a2.amountoutstanding = 0 OR a2.amountoutstanding IS NULL )
410 AND ( a3.amountoutstanding = 0 OR a3.amountoutstanding IS NULL )
413 $sth->execute($days) or die $dbh->errstr;
416 END { } # module clean-up code here (global destructor)