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);
90 In a default install of Koha the following lost values are set
95 FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that a charge has been added
96 FIXME : if no replacement price, borrower just doesn't get charged?
101 my $dbh = C4::Context->dbh();
102 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
103 my $itype = Koha::ItemTypes->find({ itemtype => Koha::Items->find($itemnumber)->effective_itemtype() });
104 my $replacementprice = $amount;
105 my $defaultreplacecost = $itype->defaultreplacecost;
106 my $processfee = $itype->processfee;
107 my $usedefaultreplacementcost = C4::Context->preference("useDefaultReplacementCost");
108 my $processingfeenote = C4::Context->preference("ProcessingFeeNote");
109 if ($usedefaultreplacementcost && $amount == 0 && $defaultreplacecost){
110 $replacementprice = $defaultreplacecost;
112 # first make sure the borrower hasn't already been charged for this item
113 # FIXME this should be more exact
114 # there is no reason a user can't lose an item, find and return it, and lost it again
115 my $existing_charges = Koha::Account::Lines->search(
117 borrowernumber => $borrowernumber,
118 itemnumber => $itemnumber,
124 unless ($existing_charges) {
126 if ($processfee && $processfee > 0){
127 my $accountline = Koha::Account::Line->new(
129 borrowernumber => $borrowernumber,
130 accountno => getnextacctno($borrowernumber),
132 amount => $processfee,
133 description => $description,
135 amountoutstanding => $processfee,
136 itemnumber => $itemnumber,
137 note => $processingfeenote,
138 manager_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0,
142 my $account_offset = Koha::Account::Offset->new(
144 debit_id => $accountline->id,
145 type => 'Processing Fee',
146 amount => $accountline->amount,
150 if ( C4::Context->preference("FinesLog") ) {
151 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
152 action => 'create_fee',
153 borrowernumber => $accountline->borrowernumber,,
154 accountno => $accountline->accountno,
155 amount => $accountline->amount,
156 description => $accountline->description,
157 accounttype => $accountline->accounttype,
158 amountoutstanding => $accountline->amountoutstanding,
159 note => $accountline->note,
160 itemnumber => $accountline->itemnumber,
161 manager_id => $accountline->manager_id,
166 if ($replacementprice > 0){
167 my $accountline = Koha::Account::Line->new(
169 borrowernumber => $borrowernumber,
170 accountno => getnextacctno($borrowernumber),
172 amount => $replacementprice,
173 description => $description,
175 amountoutstanding => $replacementprice,
176 itemnumber => $itemnumber,
177 manager_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0,
181 my $account_offset = Koha::Account::Offset->new(
183 debit_id => $accountline->id,
185 amount => $accountline->amount,
189 if ( C4::Context->preference("FinesLog") ) {
190 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
191 action => 'create_fee',
192 borrowernumber => $accountline->borrowernumber,,
193 accountno => $accountline->accountno,
194 amount => $accountline->amount,
195 description => $accountline->description,
196 accounttype => $accountline->accounttype,
197 amountoutstanding => $accountline->amountoutstanding,
198 note => $accountline->note,
199 itemnumber => $accountline->itemnumber,
200 manager_id => $accountline->manager_id,
209 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
212 C<$borrowernumber> is the patron's borrower number.
213 C<$description> is a description of the transaction.
214 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
216 C<$itemnumber> is the item involved, if pertinent; otherwise, it
217 should be the empty string.
222 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
225 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
228 # 'A' = Account Management fee
234 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
236 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
237 my $dbh = C4::Context->dbh;
239 my $accountno = getnextacctno($borrowernumber);
240 my $amountleft = $amount;
242 my $accountline = Koha::Account::Line->new(
244 borrowernumber => $borrowernumber,
245 accountno => $accountno,
248 description => $desc,
249 accounttype => $type,
250 amountoutstanding => $amountleft,
251 itemnumber => $itemnum || undef,
253 manager_id => $manager_id,
257 my $account_offset = Koha::Account::Offset->new(
259 debit_id => $accountline->id,
260 type => 'Manual Debit',
265 if ( C4::Context->preference("FinesLog") ) {
266 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
267 action => 'create_fee',
268 borrowernumber => $borrowernumber,
269 accountno => $accountno,
271 description => $desc,
272 accounttype => $type,
273 amountoutstanding => $amountleft,
275 itemnumber => $itemnum,
276 manager_id => $manager_id,
284 my ( $borrowerno, $timestamp, $accountno ) = @_;
285 my $dbh = C4::Context->dbh;
286 my $timestamp2 = $timestamp - 1;
288 my $sth = $dbh->prepare(
289 "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?"
291 $sth->execute( $borrowerno, $accountno );
294 while ( my $data = $sth->fetchrow_hashref ) {
300 #FIXME: ReversePayment should be replaced with a Void Payment feature
302 my ($accountlines_id) = @_;
303 my $dbh = C4::Context->dbh;
305 my $accountline = Koha::Account::Lines->find($accountlines_id);
306 my $amount_outstanding = $accountline->amountoutstanding;
308 my $new_amountoutstanding =
309 $amount_outstanding <= 0 ? $accountline->amount * -1 : 0;
311 $accountline->description( $accountline->description . " Reversed -" );
312 $accountline->amountoutstanding($new_amountoutstanding);
313 $accountline->store();
315 my $account_offset = Koha::Account::Offset->new(
317 credit_id => $accountline->id,
318 type => 'Reverse Payment',
319 amount => $amount_outstanding - $new_amountoutstanding,
323 if ( C4::Context->preference("FinesLog") ) {
325 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
329 $accountline->borrowernumber,
332 action => 'reverse_fee_payment',
333 borrowernumber => $accountline->borrowernumber,
334 old_amountoutstanding => $amount_outstanding,
335 new_amountoutstanding => $new_amountoutstanding,
337 accountlines_id => $accountline->id,
338 accountno => $accountline->accountno,
339 manager_id => $manager_id,
346 =head2 purge_zero_balance_fees
348 purge_zero_balance_fees( $days );
350 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
352 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
354 B<Warning:> Because fines and payments are not linked in accountlines, it is
355 possible for a fine to be deleted without the accompanying payment,
356 or vise versa. This won't affect the account balance, but might be
361 sub purge_zero_balance_fees {
365 my $dbh = C4::Context->dbh;
366 my $sth = $dbh->prepare(
368 DELETE a1 FROM accountlines a1
370 LEFT JOIN account_offsets credit_offset ON ( a1.accountlines_id = credit_offset.credit_id )
371 LEFT JOIN accountlines a2 ON ( credit_offset.debit_id = a2.accountlines_id )
373 LEFT JOIN account_offsets debit_offset ON ( a1.accountlines_id = debit_offset.debit_id )
374 LEFT JOIN accountlines a3 ON ( debit_offset.credit_id = a3.accountlines_id )
376 WHERE a1.date < date_sub(curdate(), INTERVAL ? DAY)
377 AND ( a1.amountoutstanding = 0 OR a1.amountoutstanding IS NULL )
378 AND ( a2.amountoutstanding = 0 OR a2.amountoutstanding IS NULL )
379 AND ( a3.amountoutstanding = 0 OR a3.amountoutstanding IS NULL )
382 $sth->execute($days) or die $dbh->errstr;
385 END { } # module clean-up code here (global destructor)