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);
44 &purge_zero_balance_fees
50 C4::Accounts - Functions for dealing with Koha accounts
58 The functions in this module deal with the monetary aspect of Koha,
59 including looking up and modifying the amount of money owed by a
66 $nextacct = &getnextacctno($borrowernumber);
68 Returns the next unused account number for the patron with the given
74 # FIXME - Okay, so what does the above actually _mean_?
76 my ($borrowernumber) = shift or return;
77 my $sth = C4
::Context
->dbh->prepare(
78 "SELECT accountno+1 FROM accountlines
79 WHERE (borrowernumber = ?)
80 ORDER BY accountno DESC
83 $sth->execute($borrowernumber);
84 return ($sth->fetchrow || 1);
89 In a default install of Koha the following lost values are set
94 FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that a charge has been added
95 FIXME : if no replacement price, borrower just doesn't get charged?
100 my $dbh = C4
::Context
->dbh();
101 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
102 my $itype = Koha
::ItemTypes
->find({ itemtype
=> Koha
::Items
->find($itemnumber)->effective_itemtype() });
103 my $replacementprice = $amount;
104 my $defaultreplacecost = $itype->defaultreplacecost;
105 my $processfee = $itype->processfee;
106 my $usedefaultreplacementcost = C4
::Context
->preference("useDefaultReplacementCost");
107 my $processingfeenote = C4
::Context
->preference("ProcessingFeeNote");
108 if ($usedefaultreplacementcost && $amount == 0 && $defaultreplacecost){
109 $replacementprice = $defaultreplacecost;
111 # first make sure the borrower hasn't already been charged for this item
112 # FIXME this should be more exact
113 # there is no reason a user can't lose an item, find and return it, and lost it again
114 my $existing_charges = Koha
::Account
::Lines
->search(
116 borrowernumber
=> $borrowernumber,
117 itemnumber
=> $itemnumber,
123 unless ($existing_charges) {
125 if ($processfee && $processfee > 0){
126 my $accountline = Koha
::Account
::Line
->new(
128 borrowernumber
=> $borrowernumber,
129 accountno
=> getnextacctno
($borrowernumber),
131 amount => $processfee,
132 description => $description,
134 amountoutstanding => $processfee,
135 itemnumber => $itemnumber,
136 note => $processingfeenote,
137 manager_id => C4::Context->userenv ? C4::Context->userenv->{'number
'} : 0,
141 my $account_offset = Koha::Account::Offset->new(
143 debit_id => $accountline->id,
144 type => 'Processing Fee
',
145 amount => $accountline->amount,
149 if ( C4::Context->preference("FinesLog") ) {
150 logaction("FINES", 'CREATE
',$borrowernumber,Dumper({
151 action => 'create_fee
',
152 borrowernumber => $accountline->borrowernumber,,
153 accountno => $accountline->accountno,
154 amount => $accountline->amount,
155 description => $accountline->description,
156 accounttype => $accountline->accounttype,
157 amountoutstanding => $accountline->amountoutstanding,
158 note => $accountline->note,
159 itemnumber => $accountline->itemnumber,
160 manager_id => $accountline->manager_id,
165 if ($replacementprice > 0){
166 my $accountline = Koha::Account::Line->new(
168 borrowernumber => $borrowernumber,
169 accountno => getnextacctno($borrowernumber),
171 amount
=> $replacementprice,
172 description
=> $description,
174 amountoutstanding
=> $replacementprice,
175 itemnumber
=> $itemnumber,
176 manager_id
=> C4
::Context
->userenv ? C4
::Context
->userenv->{'number'} : 0,
180 my $account_offset = Koha
::Account
::Offset
->new(
182 debit_id
=> $accountline->id,
184 amount
=> $accountline->amount,
188 if ( C4
::Context
->preference("FinesLog") ) {
189 logaction
("FINES", 'CREATE',$borrowernumber,Dumper
({
190 action
=> 'create_fee',
191 borrowernumber
=> $accountline->borrowernumber,,
192 accountno
=> $accountline->accountno,
193 amount
=> $accountline->amount,
194 description
=> $accountline->description,
195 accounttype
=> $accountline->accounttype,
196 amountoutstanding
=> $accountline->amountoutstanding,
197 note
=> $accountline->note,
198 itemnumber
=> $accountline->itemnumber,
199 manager_id
=> $accountline->manager_id,
208 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
211 C<$borrowernumber> is the patron's borrower number.
212 C<$description> is a description of the transaction.
213 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
215 C<$itemnumber> is the item involved, if pertinent; otherwise, it
216 should be the empty string.
221 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
224 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
227 # 'A' = Account Management fee
233 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
235 $manager_id = C4
::Context
->userenv->{'number'} if C4
::Context
->userenv;
236 my $dbh = C4
::Context
->dbh;
238 my $accountno = getnextacctno
($borrowernumber);
239 my $amountleft = $amount;
241 my $accountline = Koha
::Account
::Line
->new(
243 borrowernumber
=> $borrowernumber,
244 accountno
=> $accountno,
247 description => $desc,
248 accounttype => $type,
249 amountoutstanding => $amountleft,
250 itemnumber => $itemnum || undef,
252 manager_id => $manager_id,
256 my $account_offset = Koha::Account::Offset->new(
258 debit_id => $accountline->id,
259 type => 'Manual Debit
',
264 if ( C4::Context->preference("FinesLog") ) {
265 logaction("FINES", 'CREATE
',$borrowernumber,Dumper({
266 action => 'create_fee
',
267 borrowernumber => $borrowernumber,
268 accountno => $accountno,
270 description => $desc,
271 accounttype => $type,
272 amountoutstanding => $amountleft,
274 itemnumber => $itemnum,
275 manager_id => $manager_id,
282 #FIXME: ReversePayment should be replaced with a Void Payment feature
284 my ($accountlines_id) = @_;
285 my $dbh = C4::Context->dbh;
287 my $accountline = Koha::Account::Lines->find($accountlines_id);
288 my $amount_outstanding = $accountline->amountoutstanding;
290 my $new_amountoutstanding =
291 $amount_outstanding <= 0 ? $accountline->amount * -1 : 0;
293 $accountline->description( $accountline->description . " Reversed -" );
294 $accountline->amountoutstanding($new_amountoutstanding);
295 $accountline->store();
297 my $account_offset = Koha::Account::Offset->new(
299 credit_id => $accountline->id,
300 type => 'Reverse Payment
',
301 amount => $amount_outstanding - $new_amountoutstanding,
305 if ( C4::Context->preference("FinesLog") ) {
307 $manager_id = C4::Context->userenv->{'number
'} if C4::Context->userenv;
311 $accountline->borrowernumber,
314 action => 'reverse_fee_payment
',
315 borrowernumber => $accountline->borrowernumber,
316 old_amountoutstanding => $amount_outstanding,
317 new_amountoutstanding => $new_amountoutstanding,
319 accountlines_id => $accountline->id,
320 accountno => $accountline->accountno,
321 manager_id => $manager_id,
328 =head2 purge_zero_balance_fees
330 purge_zero_balance_fees( $days );
332 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
334 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
336 B<Warning:> Because fines and payments are not linked in accountlines, it is
337 possible for a fine to be deleted without the accompanying payment,
338 or vise versa. This won't affect the account balance
, but might be
343 sub purge_zero_balance_fees
{
347 my $dbh = C4
::Context
->dbh;
348 my $sth = $dbh->prepare(
350 DELETE a1 FROM accountlines a1
352 LEFT JOIN account_offsets credit_offset ON ( a1.accountlines_id = credit_offset.credit_id )
353 LEFT JOIN accountlines a2 ON ( credit_offset.debit_id = a2.accountlines_id )
355 LEFT JOIN account_offsets debit_offset ON ( a1.accountlines_id = debit_offset.debit_id )
356 LEFT JOIN accountlines a3 ON ( debit_offset.credit_id = a3.accountlines_id )
358 WHERE a1.date < date_sub(curdate(), INTERVAL ? DAY)
359 AND ( a1.amountoutstanding = 0 OR a1.amountoutstanding IS NULL )
360 AND ( a2.amountoutstanding = 0 OR a2.amountoutstanding IS NULL )
361 AND ( a3.amountoutstanding = 0 OR a3.amountoutstanding IS NULL )
364 $sth->execute($days) or die $dbh->errstr;
367 END { } # module clean-up code here (global destructor)