X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=C4%2FAccounts.pm;h=b84627b3e76ea7fda3f60538823c0f39595e238a;hb=6d1525dbf1f0783ef90274b1e925e125bededb37;hp=1d0654eb1610aa3afcf5fc1d6571f87e358d9264;hpb=9c9d0bcfe00830acc8b4386d236adf351a8a80e4;p=koha.git diff --git a/C4/Accounts.pm b/C4/Accounts.pm index 1d0654eb16..b84627b3e7 100644 --- a/C4/Accounts.pm +++ b/C4/Accounts.pm @@ -26,29 +26,28 @@ use C4::Members; use C4::Circulation qw(ReturnLostItem); use C4::Log qw(logaction); use Koha::Account; +use Koha::Account::Lines; +use Koha::Account::Offsets; +use Koha::Items; use Data::Dumper qw(Dumper); use vars qw(@ISA @EXPORT); BEGIN { - require Exporter; - @ISA = qw(Exporter); - @EXPORT = qw( - &makepayment - &manualinvoice - &getnextacctno - &getcharges - &ModNote - &getcredits - &getrefunds - &chargelostitem - &ReversePayment - &makepartialpayment - &recordpayment_selectaccts - &WriteOffFee - &purge_zero_balance_fees - ); + require Exporter; + @ISA = qw(Exporter); + @EXPORT = qw( + &manualinvoice + &getnextacctno + &getcharges + &ModNote + &getcredits + &getrefunds + &chargelostitem + &ReversePayment + &purge_zero_balance_fees + ); } =head1 NAME @@ -67,33 +66,6 @@ patron. =head1 FUNCTIONS -=head2 makepayment - - &makepayment($accountlines_id, $borrowernumber, $acctnumber, $amount, $branchcode); - -Records the fact that a patron has paid off the entire amount he or -she owes. - -C<$borrowernumber> is the patron's borrower number. C<$acctnumber> is -the account that was credited. C<$amount> is the amount paid (this is -only used to record the payment. It is assumed to be equal to the -amount owed). C<$branchcode> is the code of the branch where payment -was made. - -=cut - -#' -# FIXME - I'm not at all sure about the above, because I don't -# understand what the acct* tables in the Koha database are for. -sub makepayment { - my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_; - - my $line = Koha::Account::Lines->find( $accountlines_id ); - - return Koha::Account->new( { patron_id => $borrowernumber } ) - ->pay( { lines => [ $line ], amount => $amount, library_id => $branch, note => $payment_note } ); -} - =head2 getnextacctno $nextacct = &getnextacctno($borrowernumber); @@ -148,48 +120,122 @@ EOT =cut +=head2 chargelostitem + +In a default install of Koha the following lost values are set +1 = Lost +2 = Long overdue +3 = Lost and paid for + +FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that a charge has been added +FIXME : if no replacement price, borrower just doesn't get charged? + +=cut + sub chargelostitem{ -# lost ==1 Lost, lost==2 longoverdue, lost==3 lost and paid for -# FIXME: itemlost should be set to 3 after payment is made, should be a warning to the interface that -# a charge has been added -# FIXME : if no replacement price, borrower just doesn't get charged? my $dbh = C4::Context->dbh(); my ($borrowernumber, $itemnumber, $amount, $description) = @_; - + my $itype = Koha::ItemTypes->find({ itemtype => Koha::Items->find($itemnumber)->effective_itemtype() }); + my $replacementprice = $amount; + my $defaultreplacecost = $itype->defaultreplacecost; + my $processfee = $itype->processfee; + my $usedefaultreplacementcost = C4::Context->preference("useDefaultReplacementCost"); + my $processingfeenote = C4::Context->preference("ProcessingFeeNote"); + if ($usedefaultreplacementcost && $amount == 0 && $defaultreplacecost){ + $replacementprice = $defaultreplacecost; + } # first make sure the borrower hasn't already been charged for this item - my $sth1=$dbh->prepare("SELECT * from accountlines - WHERE borrowernumber=? AND itemnumber=? and accounttype='L'"); - $sth1->execute($borrowernumber,$itemnumber); - my $existing_charge_hashref=$sth1->fetchrow_hashref(); + # FIXME this should be more exact + # there is no reason a user can't lose an item, find and return it, and lost it again + my $existing_charges = Koha::Account::Lines->search( + { + borrowernumber => $borrowernumber, + itemnumber => $itemnumber, + accounttype => 'L', + } + )->count(); # OK, they haven't - unless ($existing_charge_hashref) { - my $manager_id = 0; - $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; - # This item is on issue ... add replacement cost to the borrower's record and mark it returned - # Note that we add this to the account even if there's no replacement price, allowing some other - # process (or person) to update it, since we don't handle any defaults for replacement prices. - my $accountno = getnextacctno($borrowernumber); - my $sth2=$dbh->prepare("INSERT INTO accountlines - (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding,itemnumber,manager_id) - VALUES (?,?,now(),?,?,'L',?,?,?)"); - $sth2->execute($borrowernumber,$accountno,$amount, - $description,$amount,$itemnumber,$manager_id); - - if ( C4::Context->preference("FinesLog") ) { - logaction("FINES", 'CREATE', $borrowernumber, Dumper({ - action => 'create_fee', - borrowernumber => $borrowernumber, - accountno => $accountno, - amount => $amount, - amountoutstanding => $amount, - description => $description, - accounttype => 'L', - itemnumber => $itemnumber, - manager_id => $manager_id, - })); + unless ($existing_charges) { + #add processing fee + if ($processfee && $processfee > 0){ + my $accountline = Koha::Account::Line->new( + { + borrowernumber => $borrowernumber, + accountno => getnextacctno($borrowernumber), + date => \'NOW()', + amount => $processfee, + description => $description, + accounttype => 'PF', + amountoutstanding => $processfee, + itemnumber => $itemnumber, + note => $processingfeenote, + manager_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0, + } + )->store(); + + my $account_offset = Koha::Account::Offset->new( + { + debit_id => $accountline->id, + type => 'Processing Fee', + amount => $accountline->amount, + } + )->store(); + + if ( C4::Context->preference("FinesLog") ) { + logaction("FINES", 'CREATE',$borrowernumber,Dumper({ + action => 'create_fee', + borrowernumber => $accountline->borrowernumber,, + accountno => $accountline->accountno, + amount => $accountline->amount, + description => $accountline->description, + accounttype => $accountline->accounttype, + amountoutstanding => $accountline->amountoutstanding, + note => $accountline->note, + itemnumber => $accountline->itemnumber, + manager_id => $accountline->manager_id, + })); + } + } + #add replace cost + if ($replacementprice > 0){ + my $accountline = Koha::Account::Line->new( + { + borrowernumber => $borrowernumber, + accountno => getnextacctno($borrowernumber), + date => \'NOW()', + amount => $replacementprice, + description => $description, + accounttype => 'L', + amountoutstanding => $replacementprice, + itemnumber => $itemnumber, + manager_id => C4::Context->userenv ? C4::Context->userenv->{'number'} : 0, + } + )->store(); + + my $account_offset = Koha::Account::Offset->new( + { + debit_id => $accountline->id, + type => 'Lost Item', + amount => $accountline->amount, + } + )->store(); + + if ( C4::Context->preference("FinesLog") ) { + logaction("FINES", 'CREATE',$borrowernumber,Dumper({ + action => 'create_fee', + borrowernumber => $accountline->borrowernumber,, + accountno => $accountline->accountno, + amount => $accountline->amount, + description => $accountline->description, + accounttype => $accountline->accounttype, + amountoutstanding => $accountline->amountoutstanding, + note => $accountline->note, + itemnumber => $accountline->itemnumber, + manager_id => $accountline->manager_id, + })); + } } - } } @@ -209,7 +255,7 @@ should be the empty string. #' # FIXME: In Koha 3.0 , the only account adjustment 'types' passed to this function -# are : +# are: # 'C' = CREDIT # 'FOR' = FORGIVEN (Formerly 'F', but 'F' is taken to mean 'FINE' elsewhere) # 'N' = New Card fee @@ -224,35 +270,32 @@ sub manualinvoice { my $manager_id = 0; $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; my $dbh = C4::Context->dbh; - my $notifyid = 0; my $insert; my $accountno = getnextacctno($borrowernumber); my $amountleft = $amount; - if ( ( $type eq 'L' ) - or ( $type eq 'F' ) - or ( $type eq 'A' ) - or ( $type eq 'N' ) - or ( $type eq 'M' ) ) - { - $notifyid = 1; - } + my $accountline = Koha::Account::Line->new( + { + borrowernumber => $borrowernumber, + accountno => $accountno, + date => \'NOW()', + amount => $amount, + description => $desc, + accounttype => $type, + amountoutstanding => $amountleft, + itemnumber => $itemnum || undef, + note => $note, + manager_id => $manager_id, + } + )->store(); - if ( $itemnum ) { - $desc .= ' ' . $itemnum; - my $sth = $dbh->prepare( - 'INSERT INTO accountlines - (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding, itemnumber,notify_id, note, manager_id) - VALUES (?, ?, now(), ?,?, ?,?,?,?,?,?)'); - $sth->execute($borrowernumber, $accountno, $amount, $desc, $type, $amountleft, $itemnum,$notifyid, $note, $manager_id) || return $sth->errstr; - } else { - my $sth=$dbh->prepare("INSERT INTO accountlines - (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding,notify_id, note, manager_id) - VALUES (?, ?, now(), ?, ?, ?, ?,?,?,?)" - ); - $sth->execute( $borrowernumber, $accountno, $amount, $desc, $type, - $amountleft, $notifyid, $note, $manager_id ); - } + my $account_offset = Koha::Account::Offset->new( + { + debit_id => $accountline->id, + type => 'Manual Debit', + amount => $amount, + } + )->store(); if ( C4::Context->preference("FinesLog") ) { logaction("FINES", 'CREATE',$borrowernumber,Dumper({ @@ -263,7 +306,6 @@ sub manualinvoice { description => $desc, accounttype => $type, amountoutstanding => $amountleft, - notify_id => $notifyid, note => $note, itemnumber => $itemnum, manager_id => $manager_id, @@ -274,19 +316,19 @@ sub manualinvoice { } sub getcharges { - my ( $borrowerno, $timestamp, $accountno ) = @_; - my $dbh = C4::Context->dbh; - my $timestamp2 = $timestamp - 1; - my $query = ""; - my $sth = $dbh->prepare( - "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?" + my ( $borrowerno, $timestamp, $accountno ) = @_; + my $dbh = C4::Context->dbh; + my $timestamp2 = $timestamp - 1; + my $query = ""; + my $sth = $dbh->prepare( + "SELECT * FROM accountlines WHERE borrowernumber=? AND accountno = ?" ); - $sth->execute( $borrowerno, $accountno ); - + $sth->execute( $borrowerno, $accountno ); + my @results; while ( my $data = $sth->fetchrow_hashref ) { - push @results,$data; - } + push @results,$data; + } return (@results); } @@ -306,7 +348,7 @@ sub getcredits { AND timestamp >=TIMESTAMP(?) AND timestamp < TIMESTAMP(?)" ); - $sth->execute( $date, $date2 ); + $sth->execute( $date, $date2 ); my @results; while ( my $data = $sth->fetchrow_hashref ) { $data->{'date'} = $data->{'timestamp'}; @@ -338,228 +380,50 @@ sub getrefunds { return (@results); } +#FIXME: ReversePayment should be replaced with a Void Payment feature sub ReversePayment { - my ( $accountlines_id ) = @_; + my ($accountlines_id) = @_; my $dbh = C4::Context->dbh; - my $sth = $dbh->prepare('SELECT * FROM accountlines WHERE accountlines_id = ?'); - $sth->execute( $accountlines_id ); - my $row = $sth->fetchrow_hashref(); - my $amount_outstanding = $row->{'amountoutstanding'}; - - if ( $amount_outstanding <= 0 ) { - $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = amount * -1, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?'); - $sth->execute( $accountlines_id ); - } else { - $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding = 0, description = CONCAT( description, " Reversed -" ) WHERE accountlines_id = ?'); - $sth->execute( $accountlines_id ); - } - - if ( C4::Context->preference("FinesLog") ) { - my $manager_id = 0; - $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; - - if ( $amount_outstanding <= 0 ) { - $row->{'amountoutstanding'} *= -1; - } else { - $row->{'amountoutstanding'} = '0'; - } - $row->{'description'} .= ' Reversed -'; - logaction("FINES", 'MODIFY', $row->{'borrowernumber'}, Dumper({ - action => 'reverse_fee_payment', - borrowernumber => $row->{'borrowernumber'}, - old_amountoutstanding => $row->{'amountoutstanding'}, - new_amountoutstanding => 0 - $amount_outstanding,, - accountlines_id => $row->{'accountlines_id'}, - accountno => $row->{'accountno'}, - manager_id => $manager_id, - })); - - } - -} - -=head2 recordpayment_selectaccts + my $accountline = Koha::Account::Lines->find($accountlines_id); + my $amount_outstanding = $accountline->amountoutstanding; - recordpayment_selectaccts($borrowernumber, $payment,$accts); + my $new_amountoutstanding = + $amount_outstanding <= 0 ? $accountline->amount * -1 : 0; -Record payment by a patron. C<$borrowernumber> is the patron's -borrower number. C<$payment> is a floating-point number, giving the -amount that was paid. C<$accts> is an array ref to a list of -accountnos which the payment can be recorded against + $accountline->description( $accountline->description . " Reversed -" ); + $accountline->amountoutstanding($new_amountoutstanding); + $accountline->store(); -Amounts owed are paid off oldest first. That is, if the patron has a -$1 fine from Feb. 1, another $1 fine from Mar. 1, and makes a payment -of $1.50, then the oldest fine will be paid off in full, and $0.50 -will be credited to the next one. - -=cut - -sub recordpayment_selectaccts { - my ( $borrowernumber, $amount, $accts, $note ) = @_; - - my @lines = Koha::Account::Lines->search( - { - borrowernumber => $borrowernumber, - amountoutstanding => { '<>' => 0 }, - accountno => { 'IN' => $accts }, - }, - { order_by => 'date' } - ); - - return Koha::Account->new( + my $account_offset = Koha::Account::Offset->new( { - patron_id => $borrowernumber, + credit_id => $accountline->id, + type => 'Reverse Payment', + amount => $amount_outstanding - $new_amountoutstanding, } - )->pay( - { - amount => $amount, - lines => \@lines, - note => $note - } - ); -} - -# makepayment needs to be fixed to handle partials till then this separate subroutine -# fills in -sub makepartialpayment { - my ( $accountlines_id, $borrowernumber, $accountno, $amount, $user, $branch, $payment_note ) = @_; - my $manager_id = 0; - $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; - if (!$amount || $amount < 0) { - return; - } - $payment_note //= ""; - my $dbh = C4::Context->dbh; - - my $nextaccntno = getnextacctno($borrowernumber); - my $newamtos = 0; - - my $data = $dbh->selectrow_hashref( - 'SELECT * FROM accountlines WHERE accountlines_id=?',undef,$accountlines_id); - my $new_outstanding = $data->{amountoutstanding} - $amount; - - my $update = 'UPDATE accountlines SET amountoutstanding = ? WHERE accountlines_id = ? '; - $dbh->do( $update, undef, $new_outstanding, $accountlines_id); - - if ( C4::Context->preference("FinesLog") ) { - logaction("FINES", 'MODIFY', $borrowernumber, Dumper({ - action => 'fee_payment', - borrowernumber => $borrowernumber, - old_amountoutstanding => $data->{'amountoutstanding'}, - new_amountoutstanding => $new_outstanding, - amount_paid => $data->{'amountoutstanding'} - $new_outstanding, - accountlines_id => $data->{'accountlines_id'}, - accountno => $data->{'accountno'}, - manager_id => $manager_id, - })); - } - - # create new line - my $insert = 'INSERT INTO accountlines (borrowernumber, accountno, date, amount, ' - . 'description, accounttype, amountoutstanding, itemnumber, manager_id, note) ' - . ' VALUES (?, ?, now(), ?, ?, ?, 0, ?, ?, ?)'; - - $dbh->do( $insert, undef, $borrowernumber, $nextaccntno, -$amount, - '', 'Pay', $data->{'itemnumber'}, $manager_id, $payment_note); - - UpdateStats({ - branch => $branch, - type => 'payment', - amount => $amount, - borrowernumber => $borrowernumber, - accountno => $accountno - }); - - if ( C4::Context->preference("FinesLog") ) { - logaction("FINES", 'CREATE',$borrowernumber,Dumper({ - action => 'create_payment', - borrowernumber => $user, - accountno => $nextaccntno, - amount => 0 - $amount, - accounttype => 'Pay', - itemnumber => $data->{'itemnumber'}, - accountlines_paid => [ $data->{'accountlines_id'} ], - manager_id => $manager_id, - })); - } - - return; -} - -=head2 WriteOffFee - - WriteOffFee( $borrowernumber, $accountline_id, $itemnum, $accounttype, $amount, $branch, $payment_note ); - -Write off a fine for a patron. -C<$borrowernumber> is the patron's borrower number. -C<$accountline_id> is the accountline_id of the fee to write off. -C<$itemnum> is the itemnumber of of item whose fine is being written off. -C<$accounttype> is the account type of the fine being written off. -C<$amount> is a floating-point number, giving the amount that is being written off. -C<$branch> is the branchcode of the library where the writeoff occurred. -C<$payment_note> is the note to attach to this payment - -=cut - -sub WriteOffFee { - my ( $borrowernumber, $accountlines_id, $itemnum, $accounttype, $amount, $branch, $payment_note ) = @_; - $payment_note //= ""; - $branch ||= C4::Context->userenv->{branch}; - my $manager_id = 0; - $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; - - # if no item is attached to fine, make sure to store it as a NULL - $itemnum ||= undef; - - my ( $sth, $query ); - my $dbh = C4::Context->dbh(); - - $query = " - UPDATE accountlines SET amountoutstanding = 0 - WHERE accountlines_id = ? AND borrowernumber = ? - "; - $sth = $dbh->prepare( $query ); - $sth->execute( $accountlines_id, $borrowernumber ); + )->store(); if ( C4::Context->preference("FinesLog") ) { - logaction("FINES", 'MODIFY', $borrowernumber, Dumper({ - action => 'fee_writeoff', - borrowernumber => $borrowernumber, - accountlines_id => $accountlines_id, - manager_id => $manager_id, - })); - } - - $query =" - INSERT INTO accountlines - ( borrowernumber, accountno, itemnumber, date, amount, description, accounttype, manager_id, note ) - VALUES ( ?, ?, ?, NOW(), ?, 'Writeoff', 'W', ?, ? ) - "; - $sth = $dbh->prepare( $query ); - my $acct = getnextacctno($borrowernumber); - $sth->execute( $borrowernumber, $acct, $itemnum, $amount, $manager_id, $payment_note ); + my $manager_id = 0; + $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; - if ( C4::Context->preference("FinesLog") ) { - logaction("FINES", 'CREATE',$borrowernumber,Dumper({ - action => 'create_writeoff', - borrowernumber => $borrowernumber, - accountno => $acct, - amount => 0 - $amount, - accounttype => 'W', - itemnumber => $itemnum, - accountlines_paid => [ $accountlines_id ], - manager_id => $manager_id, - })); + logaction( + "FINES", 'MODIFY', + $accountline->borrowernumber, + Dumper( + { + action => 'reverse_fee_payment', + borrowernumber => $accountline->borrowernumber, + old_amountoutstanding => $amount_outstanding, + new_amountoutstanding => $new_amountoutstanding, + , + accountlines_id => $accountline->id, + accountno => $accountline->accountno, + manager_id => $manager_id, + } + ) + ); } - - UpdateStats({ - branch => $branch, - type => 'writeoff', - amount => $amount, - borrowernumber => $borrowernumber} - ); - } =head2 purge_zero_balance_fees