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);
43 &purge_zero_balance_fees
49 C4::Accounts - Functions for dealing with Koha accounts
57 The functions in this module deal with the monetary aspect of Koha,
58 including looking up and modifying the amount of money owed by a
65 $nextacct = &getnextacctno($borrowernumber);
67 Returns the next unused account number for the patron with the given
73 # FIXME - Okay, so what does the above actually _mean_?
75 my ($borrowernumber) = shift or return;
76 my $sth = C4::Context->dbh->prepare(
77 "SELECT accountno+1 FROM accountlines
78 WHERE (borrowernumber = ?)
79 ORDER BY accountno DESC
82 $sth->execute($borrowernumber);
83 return ($sth->fetchrow || 1);
88 In a default install of Koha the following lost values are set
93 FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that a charge has been added
94 FIXME : if no replacement price, borrower just doesn't get charged?
99 my $dbh = C4::Context->dbh();
100 my ($borrowernumber, $itemnumber, $amount, $description) = @_;
101 my $itype = Koha::ItemTypes->find({ itemtype => Koha::Items->find($itemnumber)->effective_itemtype() });
102 my $replacementprice = $amount;
103 my $defaultreplacecost = $itype->defaultreplacecost;
104 my $processfee = $itype->processfee;
105 my $usedefaultreplacementcost = C4::Context->preference("useDefaultReplacementCost");
106 my $processingfeenote = C4::Context->preference("ProcessingFeeNote");
107 if ($usedefaultreplacementcost && $amount == 0 && $defaultreplacecost){
108 $replacementprice = $defaultreplacecost;
111 my $branchcode = C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
113 # first make sure the borrower hasn't already been charged for this item
114 # FIXME this should be more exact
115 # there is no reason a user can't lose an item, find and return it, and lost it again
116 my $existing_charges = Koha::Account::Lines->search(
118 borrowernumber => $borrowernumber,
119 itemnumber => $itemnumber,
125 unless ($existing_charges) {
126 my $checkout = Koha::Checkouts->find({ itemnumber => $itemnumber });
127 my $issue_id = $checkout ? $checkout->issue_id : undef;
129 if ($processfee && $processfee > 0){
130 my $accountline = Koha::Account::Line->new(
132 borrowernumber => $borrowernumber,
133 issue_id => $issue_id,
134 accountno => getnextacctno($borrowernumber),
136 amount => $processfee,
137 description => $description,
139 amountoutstanding => $processfee,
140 itemnumber => $itemnumber,
141 note => $processingfeenote,
142 manager_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0,
143 branchcode => $branchcode,
147 my $account_offset = Koha::Account::Offset->new(
149 debit_id => $accountline->id,
150 type => 'Processing Fee',
151 amount => $accountline->amount,
155 if ( C4::Context->preference("FinesLog") ) {
156 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
157 action => 'create_fee',
158 borrowernumber => $accountline->borrowernumber,,
159 accountno => $accountline->accountno,
160 amount => $accountline->amount,
161 description => $accountline->description,
162 accounttype => $accountline->accounttype,
163 amountoutstanding => $accountline->amountoutstanding,
164 note => $accountline->note,
165 itemnumber => $accountline->itemnumber,
166 manager_id => $accountline->manager_id,
171 if ($replacementprice > 0){
172 my $accountline = Koha::Account::Line->new(
174 borrowernumber => $borrowernumber,
175 issue_id => $issue_id,
176 accountno => getnextacctno($borrowernumber),
178 amount => $replacementprice,
179 description => $description,
181 amountoutstanding => $replacementprice,
182 itemnumber => $itemnumber,
183 manager_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0,
184 branchcode => $branchcode,
188 my $account_offset = Koha::Account::Offset->new(
190 debit_id => $accountline->id,
192 amount => $accountline->amount,
196 if ( C4::Context->preference("FinesLog") ) {
197 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
198 action => 'create_fee',
199 borrowernumber => $accountline->borrowernumber,,
200 accountno => $accountline->accountno,
201 amount => $accountline->amount,
202 description => $accountline->description,
203 accounttype => $accountline->accounttype,
204 amountoutstanding => $accountline->amountoutstanding,
205 note => $accountline->note,
206 itemnumber => $accountline->itemnumber,
207 manager_id => $accountline->manager_id,
216 &manualinvoice($borrowernumber, $itemnumber, $description, $type,
219 C<$borrowernumber> is the patron's borrower number.
220 C<$description> is a description of the transaction.
221 C<$type> may be one of C<CS>, C<CB>, C<CW>, C<CF>, C<CL>, C<N>, C<L>,
223 C<$itemnumber> is the item involved, if pertinent; otherwise, it
224 should be the empty string.
229 # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function
232 # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere)
235 # 'A' = Account Management fee
241 my ( $borrowernumber, $itemnum, $desc, $type, $amount, $note ) = @_;
243 $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv;
244 my $dbh = C4::Context->dbh;
246 my $accountno = getnextacctno($borrowernumber);
247 my $amountleft = $amount;
249 my $branchcode = C4::Context->userenv ? C4::Context->userenv->{'branch'} : undef;
251 my $accountline = Koha::Account::Line->new(
253 borrowernumber => $borrowernumber,
254 accountno => $accountno,
257 description => $desc,
258 accounttype => $type,
259 amountoutstanding => $amountleft,
260 itemnumber => $itemnum || undef,
262 manager_id => $manager_id,
263 branchcode => $branchcode,
267 my $account_offset = Koha::Account::Offset->new(
269 debit_id => $accountline->id,
270 type => 'Manual Debit',
275 if ( C4::Context->preference("FinesLog") ) {
276 logaction("FINES", 'CREATE',$borrowernumber,Dumper({
277 action => 'create_fee',
278 borrowernumber => $borrowernumber,
279 accountno => $accountno,
281 description => $desc,
282 accounttype => $type,
283 amountoutstanding => $amountleft,
285 itemnumber => $itemnum,
286 manager_id => $manager_id,
293 =head2 purge_zero_balance_fees
295 purge_zero_balance_fees( $days );
297 Delete accountlines entries where amountoutstanding is 0 or NULL which are more than a given number of days old.
299 B<$days> -- Zero balance fees older than B<$days> days old will be deleted.
301 B<Warning:> Because fines and payments are not linked in accountlines, it is
302 possible for a fine to be deleted without the accompanying payment,
303 or vise versa. This won't affect the account balance, but might be
308 sub purge_zero_balance_fees {
312 my $dbh = C4::Context->dbh;
313 my $sth = $dbh->prepare(
315 DELETE a1 FROM accountlines a1
317 LEFT JOIN account_offsets credit_offset ON ( a1.accountlines_id = credit_offset.credit_id )
318 LEFT JOIN accountlines a2 ON ( credit_offset.debit_id = a2.accountlines_id )
320 LEFT JOIN account_offsets debit_offset ON ( a1.accountlines_id = debit_offset.debit_id )
321 LEFT JOIN accountlines a3 ON ( debit_offset.credit_id = a3.accountlines_id )
323 WHERE a1.date < date_sub(curdate(), INTERVAL ? DAY)
324 AND ( a1.amountoutstanding = 0 OR a1.amountoutstanding IS NULL )
325 AND ( a2.amountoutstanding = 0 OR a2.amountoutstanding IS NULL )
326 AND ( a3.amountoutstanding = 0 OR a3.amountoutstanding IS NULL )
329 $sth->execute($days) or die $dbh->errstr;
332 END { } # module clean-up code here (global destructor)