From c75b0d3c56832a58fd7f8a45a2681b746354d035 Mon Sep 17 00:00:00 2001 From: Colin Campbell <colin.campbell@ptfs-europe.com> Date: Fri, 26 Mar 2010 12:21:42 +0000 Subject: [PATCH] Bug 3498 Allow Partial Payment in Fines Content-Type: text/plain; charset="utf-8" Allow partial payment of outstanding fines either against individual fine entries or as a lump payment. Sponsered by East Brunswick Public Library, East Brunswick, NJ, USA --- C4/Accounts.pm | 101 ++++++- .../intranet-tmpl/prog/en/modules/members/pay.tmpl | 39 ++- .../prog/en/modules/members/paycollect.tmpl | 221 ++++++++++++ members/pay.pl | 371 +++++++++++++------- members/paycollect.pl | 188 ++++++++++ 5 files changed, 783 insertions(+), 137 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tmpl create mode 100755 members/paycollect.pl diff --git a/C4/Accounts.pm b/C4/Accounts.pm index bbc6c00..bce9c19 100644 --- a/C4/Accounts.pm +++ b/C4/Accounts.pm @@ -35,8 +35,9 @@ BEGIN { @EXPORT = qw( &recordpayment &makepayment &manualinvoice &getnextacctno &reconcileaccount &getcharges &getcredits - &getrefunds &chargelostitem + &getrefunds &chargelostitem makepartialpayment &ReversePayment + recordpayment_selectaccts ); # removed &fixaccounts } @@ -132,6 +133,70 @@ sub recordpayment { $sth->finish; } +=head2 recordpayment_selectaccts + + recordpayment_selectaccts($borrowernumber, $payment,$accts); + +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 + +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 ) = @_; + + my $dbh = C4::Context->dbh; + my $newamtos = 0; + my $accdata = q{}; + my $branch = C4::Context->userenv->{branch}; + my $amountleft = $amount; + my $sql = 'SELECT * FROM accountlines WHERE (borrowernumber = ?) ' . + 'AND (amountoutstanding<>0) '; + if (@{$accts} ) { + $sql .= ' AND accountno IN ( ' . join ',', @{$accts}; + $sql .= ' ) '; + } + $sql .= ' ORDER BY date'; + # begin transaction + my $nextaccntno = getnextacctno($borrowernumber); + + # get lines with outstanding amounts to offset + my $rows = $dbh->selectall_arrayref($sql, { Slice => {} }, $borrowernumber); + + # offset transactions + my $sth = $dbh->prepare('UPDATE accountlines SET amountoutstanding= ? ' . + 'WHERE (borrowernumber = ?) AND (accountno=?)'); + for my $accdata ( @{$rows} ) { + if ($amountleft == 0) { + last; + } + if ( $accdata->{amountoutstanding} < $amountleft ) { + $newamtos = 0; + $amountleft -= $accdata->{amountoutstanding}; + } + else { + $newamtos = $accdata->{amountoutstanding} - $amountleft; + $amountleft = 0; + } + my $thisacct = $accdata->{accountno}; + $sth->execute( $newamtos, $borrowernumber, $thisacct ); + } + + # create new line + $sql = 'INSERT INTO accountlines ' . + '(borrowernumber, accountno,date,amount,description,accounttype,amountoutstanding) ' . + q|VALUES (?,?,now(),?,'Payment,thanks','Pay',?)|; + $dbh->do($sql,{},$borrowernumber, $nextaccntno, 0 - $amount, 0 - $amountleft ); + UpdateStats( $branch, 'payment', $amount, '', '', '', $borrowernumber, $nextaccntno ); + return; +} =head2 makepayment &makepayment($borrowernumber, $acctnumber, $amount, $branchcode); @@ -207,6 +272,39 @@ sub makepayment { } } +# makepayment needs to be fixed to handle partials till then this separate subroutine +# fills in +sub makepartialpayment { + my ( $borrowernumber, $accountno, $amount, $user, $branch ) = @_; + if (!$amount || $amount < 0) { + return; + } + my $dbh = C4::Context->dbh; + + my $nextaccntno = getnextacctno($borrowernumber); + my $newamtos = 0; + + my $data = $dbh->selectrow_hashref( + 'SELECT * FROM accountlines WHERE borrowernumber=? AND accountno=?',undef,$borrowernumber,$accountno); + my $new_outstanding = $data->{amountoutstanding} - $amount; + + my $update = 'UPDATE accountlines SET amountoutstanding = ? WHERE borrowernumber = ? ' + . ' AND accountno = ?'; + $dbh->do( $update, undef, $new_outstanding, $borrowernumber, $accountno); + + # create new line + my $insert = 'INSERT INTO accountlines (borrowernumber, accountno, date, amount, ' + . 'description, accounttype, amountoutstanding) ' + . ' VALUES (?, ?, now(), ?, ?, ?, 0)'; + + $dbh->do( $insert, undef, $borrowernumber, $nextaccntno, $amount, + "Payment, thanks - $user", 'Pay'); + + UpdateStats( $user, 'payment', $amount, '', '', '', $borrowernumber, $accountno ); + + return; +} + =head2 getnextacctno $nextacct = &getnextacctno($borrowernumber); @@ -227,6 +325,7 @@ sub getnextacctno ($) { LIMIT 1" ); $sth->execute($borrowernumber); + return ($sth->fetchrow || 1); } diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tmpl index 1177ba2..057333a 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tmpl +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tmpl @@ -9,7 +9,7 @@ <div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Pay Fines for <!-- TMPL_VAR name="firstname" --> <!-- TMPL_VAR name="surname" --></div> <div id="doc3" class="yui-t2"> - + <div id="bd"> <div id="yui-main"> <div class="yui-b"> @@ -31,6 +31,7 @@ <table> <tr> <th>Fines & Charges</th> + <th>Sel</th> <th>Description</th> <th>Account Type</th> <th>Notify id</th> @@ -44,13 +45,20 @@ <tr> <td> <!-- TMPL_IF NAME="net_balance" --> - <select name="payfine<!-- TMPL_VAR name="i" -->"> + <!--<select name="payfine<!-- TMPL_VAR name="i" -->"> <option value="no">Unpaid</option> - <option value="yes">Paid</option> - <option value="wo">Writeoff</option> - </select> + <option value="yes">Paid</option> --> + <input type="submit" name="pay_indiv<!-- TMPL_VAR name="i" -->"i value="Pay" /> + <!-- TMPL_IF NAME="CAN_user_updatecharges_writeoff_charges" --> + <input type="submit" name="wo_indiv<!-- TMPL_VAR name="i" -->"i value="Writeoff" /> + <!--<option value="wo">Writeoff</option> --> + <!-- /TMPL_IF --> + <!--</select> --> <!-- /TMPL_IF --> + <input type="hidden" name="line_id<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="i" -->" /> <input type="hidden" name="itemnumber<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="itemnumber" -->" /> + <input type="hidden" name="description<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="description" -->" /> + <input type="hidden" name="title<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="title" -->" /> <input type="hidden" name="accounttype<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="accounttype" -->" /> <input type="hidden" name="amount<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="amount" -->" /> <input type="hidden" name="out<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="amountoutstanding" -->" /> @@ -60,6 +68,11 @@ <input type="hidden" name="notify_level<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="notify_level" -->" /> <input type="hidden" name="totals<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="totals" -->" /> </td> + <td> + <!-- TMPL_IF NAME="net_balance" --> + <input type="checkbox" checked="checked" name="incl_par<!-- TMPL_VAR name="i" -->" /> + <!-- /TMPL_IF --> + </td> <td><!-- TMPL_VAR name="description" --> <!-- TMPL_VAR name="title" escape="html" --></td> <td><!-- TMPL_VAR name="accounttype" --></td> <td><!-- TMPL_VAR name="notify_id" --></td> @@ -71,17 +84,27 @@ <!-- TMPL_IF NAME="total"--> <tr> - <td colspan="6">Sub Total</td> + <td colspan="7">Sub Total</td> <td><!-- TMPL_VAR name="total" --></td> </tr> <!--/TMPL_IF--> <!-- /TMPL_LOOP --> <tr> - <td colspan="6">Total Due</td> + <td colspan="7">Total Due</td> <td><!-- TMPL_VAR name="total" --></td> </tr> </table> -<fieldset class="action"><input type="submit" name="submit" value="Make Payment" class="submit" /> <a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->">Cancel</a></fieldset></form><!-- TMPL_ELSE --><p><!-- TMPL_VAR NAME="firstname" --> <!-- TMPL_VAR NAME="surname" --> has no outstanding fines.</p><!-- /TMPL_IF --> +<!-- <p>On All Or Part Of The Total Sum Due:</p> --> +<fieldset class="action"> + <input type="submit" name="paycollect" value="Pay Amount" class="submit" /> +<!-- TMPL_IF NAME="CAN_user_updatecharges_writeoff_charges" --> + <input type="submit" name="woall" value="Writeoff All" class="submit" /> +<!-- /TMPL_IF --> + <input type="submit" name="payselected" value="Pay Selected" class="submit" /> + <a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->"> + Cancel</a> +</fieldset> +</form><!-- TMPL_ELSE --><p><!-- TMPL_VAR NAME="firstname" --> <!-- TMPL_VAR NAME="surname" --> has no outstanding fines.</p><!-- /TMPL_IF --> </div></div> </div> diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tmpl new file mode 100644 index 0000000..3bf9891 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tmpl @@ -0,0 +1,221 @@ +<!-- TMPL_INCLUDE NAME="doc-head-open.inc" --> +<title>Koha › Patrons › Collect Fine Payment for <!-- TMPL_VAR NAME="firstname" --> <!-- TMPL_VAR NAME="surname" --></title> +<!-- TMPL_INCLUDE NAME="doc-head-close.inc" --> +<script type= "text/javascript"> +//<![CDATA[ +function moneyFormat(textObj) { + var newValue = textObj.value; + var decAmount = ""; + var dolAmount = ""; + var decFlag = false; + var aChar = ""; + + for(i=0; i < newValue.length; i++) { + aChar = newValue.substring(i, i+1); + if (aChar >= "0" && aChar <= "9") { + if(decFlag) { + decAmount = "" + decAmount + aChar; + } + else { + dolAmount = "" + dolAmount + aChar; + } + } + if (aChar == ".") { + if (decFlag) { + dolAmount = ""; + break; + } + decFlag = true; + } + } + + if (dolAmount == "") { + dolAmount = "0"; + } +// Strip leading 0s + if (dolAmount.length > 1) { + while(dolAmount.length > 1 && dolAmount.substring(0,1) == "0") { + dolAmount = dolAmount.substring(1,dolAmount.length); + } + } + if (decAmount.length > 2) { + decAmount = decAmount.substring(0,2); + } +// Pad right side + if (decAmount.length == 1) { + decAmount = decAmount + "0"; + } + if (decAmount.length == 0) { + decAmount = decAmount + "00"; + } + + textObj.value = dolAmount + "." + decAmount; +} +//]]> +</script> +</head> +<body> +<!-- TMPL_INCLUDE NAME="header.inc" --> +<!-- TMPL_INCLUDE NAME="patron-search.inc" --> +<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a> › Pay Fines for <!-- TMPL_VAR name="firstname" --> <!-- TMPL_VAR name="surname" --></div> + +<div id="doc3" class="yui-t2"> + +<div id="bd"> +<div id="yui-main"> +<div class="yui-b"> +<!-- TMPL_INCLUDE NAME="members-toolbar.inc" --> + + +<!-- The manual invoice and credit buttons --> +<div class="toptabs"> +<ul class="ui-tabs-nav"> +<li><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->">Account</a></li> +<li class="ui-tabs-selected"><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->" >Pay fines</a></li> +<li><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->" >Create Manual Invoice</a></li> +<li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->" >Create Manual Credit</a></li> +</ul> +<div class="tabs-container"> + +<!--<form action="/cgi-bin/koha/members/paycollect.pl" method="post"> --> +<!-- TMPL_IF NAME="pay_individual" --> +<form name="payindivfine" onsubmit="return validatePayment(this);" method="post" action="/cgi-bin/koha/members/paycollect.pl"> +<input type="hidden" name="borrowernumber" id="borrowernumber" value="<!-- TMPL_VAR name="borrowernumber" -->" /> +<input type="hidden" name="pay_individual" id="pay_individual" value="<!-- TMPL_VAR name="pay_individual" -->" /> +<input type="hidden" name="description" id="description" value="<!-- TMPL_VAR name="description" -->" /> +<input type="hidden" name="accounttype" id="accounttype" value="<!-- TMPL_VAR name="accounttype" -->" /> +<input type="hidden" name="notify_id" id="notify_id" value="<!-- TMPL_VAR name="notify_id" -->" /> +<input type="hidden" name="notify_level" id="notify_level" value="<!-- TMPL_VAR name="notify_level" -->" /> +<input type="hidden" name="amount" id="amount" value="<!-- TMPL_VAR name="amount" -->" /> +<input type="hidden" name="amountoutstanding" id="amountoutstanding" value="<!-- TMPL_VAR name="amountoutstanding" -->" /> +<input type="hidden" name="accountno" id="accountno" value="<!-- TMPL_VAR name="accountno" -->" /> +<input type="hidden" name="title" id="title" value="<!-- TMPL_VAR name="title" -->" /> +<table> +<tr> +<th>Description</th> +<th>Account Type</th> +<th>Notify id</th> +<th>Level</th> +<th>Amount</th> +<th>Amount Outstanding</th> +</tr> +<tr> +<td> +<!-- TMPL_VAR NAME="description" --> <!-- TMPL_VAR="title" escape="html" --> +</td> +<td><!-- TMPL_VAR name="accounttype" --></td> +<td><!-- TMPL_VAR name="notify_id" --></td> +<td><!-- TMPL_VAR name="notify_level" --></td> +<td class="debit"><!-- TMPL_VAR name="amount" --></td> +<td class="debit"><!-- TMPL_VAR name="amountoutstanding" --></td> +</tr> +<tr> +<td>Total Amount Payable : </td> +<td> +<!-- TMPL_VAR NAME="amountoutstanding" --> +</td> +</tr> +<tr><td> </td></tr> +<tr> +<td>Collect From Patron: </td> +<td> +<!-- default to paying all --> +<input name="paid" id="paid" value="<!-- TMPL_VAR NAME="amountoutstanding" -->" onchange="moneyFormat(document.payindivfine.paid)"/> +</td> +</tr> +<tr><td> </td></tr> +<tr> +<td rowspan="2"> +<input type="submit" name="submitbutton" value="Confirm" /> +<a class="cancel" href="/cgi-bin/koha/members/pay.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->">Cancel</a> +</td> +</tr> + +</table> +<!-- TMPL_ELSIF NAME="writeoff_individual"--> +<form name="woindivfine" action="/cgi-bin/koha/members/pay.pl" method="post" > +<input type="hidden" name="borrowernumber" id="borrowernumber" value="<!-- TMPL_VAR name="borrowernumber" -->" /> +<input type="hidden" name="pay_individual" id="pay_individual" value="<!-- TMPL_VAR name="pay_individual" -->" /> +<input type="hidden" name="description" id="description" value="<!-- TMPL_VAR name="description" -->" /> +<input type="hidden" name="accounttype" id="accounttype" value="<!-- TMPL_VAR name="accounttype" -->" /> +<input type="hidden" name="notify_id" id="notify_id" value="<!-- TMPL_VAR name="notify_id" -->" /> +<input type="hidden" name="notify_level" id="notify_level" value="<!-- TMPL_VAR name="notify_level" -->" /> +<input type="hidden" name="amount" id="amount" value="<!-- TMPL_VAR name="amount" -->" /> +<input type="hidden" name="amountoutstanding" id="amountoutstanding" value="<!-- TMPL_VAR name="amountoutstanding" -->" /> +<input type="hidden" name="accountno" id="accountno" value="<!-- TMPL_VAR name="accountno" -->" /> +<input type="hidden" name="title" id="title" value="<!-- TMPL_VAR name="title" -->" /> +<table> +<tr> +<th>Description</th> +<th>Account Type</th> +<th>Notify id</th> +<th>Level</th> +<th>Amount</th> +<th>Amount Outstanding</th> +</tr> +<tr> +<td> +<!-- TMPL_VAR NAME="description" --> <!-- TMPL_VAR="title" escape="html" --> +</td> +<td><!-- TMPL_VAR name="accounttype" --></td> +<td><!-- TMPL_VAR name="notify_id" --></td> +<td><!-- TMPL_VAR name="notify_level" --></td> +<td class="debit"><!-- TMPL_VAR name="amount" --></td> +<td class="debit"><!-- TMPL_VAR name="amountoutstanding" --></td> +</tr> +<tr><td> </td></tr> +<tr><td rowspan="2"><strong>Writeoff This Charge?</strong></td></tr> +<tr><td> </td></tr> +<tr> +<td rowspan="2"> +<input type="submit" name="confirm_writeoff" id="confirm_writeoff" value="Confirm" /> +<a class="cancel" href="/cgi-bin/koha/members/pay.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->">Cancel</a> +</td> +</tr> + +</table> +<!-- TMPL_ELSE --> + +<form name="payfine" onsubmit="return validatePayment(this);" method="post" action="/cgi-bin/koha/members/paycollect.pl"> +<input type="hidden" name="borrowernumber" id="borrowernumber" value="<!-- TMPL_VAR name="borrowernumber" -->" /> +<input type="hidden" name="selected_accts" id="selected_accts" value="<!-- TMPL_VAR name="selected_accts" --> /> +<input type="hidden" name="total" id="total" value="<!-- TMPL_VAR name="total" -->" /> + +<table> +<!-- TMPL_IF NAME="error" --> +<tr><td><!-- TMPL_VAR NAME="error" --></td></tr> +<!-- /TMPL_IF --> +<tr> +<td>Total Amount Outstanding : </td> +<td> +<!-- TMPL_VAR NAME="total" --> +</td> +</tr> +<tr><td> </td></tr> +<tr> +<td>Collect From Patron: </td> +<td> +<!-- default to paying all --> +<input name="paid" id="paid" value="<!-- TMPL_VAR NAME="total" -->" onchange="moneyFormat(document.payfine.paid)"/> +</td> +</tr> +<tr><td> </td></tr> +<tr> +<td rowspan="2"> +<input type="submit" name="submitbutton" value="Confirm" /> +<a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->">Cancel</a> +</td> +</tr> +</table> +</form> +<!-- /TMPL_IF --> +</div></div> + +</div> +</div> + +<div class="yui-b"> +<!-- TMPL_INCLUDE NAME="circ-menu.inc" --> +</div> +</div> +<!-- TMPL_INCLUDE NAME="intranet-bottom.inc" --> diff --git a/members/pay.pl b/members/pay.pl index 5a36bd7..1bfbead 100755 --- a/members/pay.pl +++ b/members/pay.pl @@ -39,185 +39,300 @@ use C4::Koha; use C4::Overdues; use C4::Branch; # GetBranches -my $input = new CGI; +my $input = CGI->new(); my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { - template_name => "members/pay.tmpl", + template_name => 'members/pay.tmpl', query => $input, - type => "intranet", + type => 'intranet', authnotrequired => 0, flagsrequired => { borrowers => 1, updatecharges => 1 }, debug => 1, } ); +my @nam = $input->param; my $borrowernumber = $input->param('borrowernumber'); -if ( $borrowernumber eq '' ) { +if ( !$borrowernumber ) { $borrowernumber = $input->param('borrowernumber0'); } # get borrower details my $data = GetMember( borrowernumber => $borrowernumber ); my $user = $input->remote_user; +$user ||= q{}; # get account details my $branches = GetBranches(); my $branch = GetBranch( $input, $branches ); +my $co_wr = $input->param('confirm_writeoff'); +my $paycollect = $input->param('paycollect'); +if ($paycollect) { + print $input->redirect("/cgi-bin/koha/members/paycollect.pl?borrowernumber=$borrowernumber" ); +} +my $payselected = $input->param('payselected'); +if ($payselected) { + my @lines; + foreach (@nam) { + if ( /^incl_par_(\d+)$/) { + push @lines, $1; + } + } + my @lines_to_pay; + my $amt = 0; + for (@lines) { + push @lines_to_pay, $input->param("accountno_$_"); + $amt += $input->param("out_$_"); + } + $amt = '&amt=' . $amt; + my $sel = '&selected=' . join ',', @lines_to_pay; + my $redirect = "/cgi-bin/koha/members/paycollect.pl?borrowernumber=$borrowernumber" . $amt . $sel; + + print $input->redirect($redirect); + +} + +my $wo_all = $input->param('woall'); # writeoff all fines +if ($wo_all) { + writeoff_all(); +} elsif ($co_wr) { + my $accountno = $input->param('accountno'); + my $itemno = $input->param('itemnumber'); + my $account_type = $input->param('accounttype'); + my $amount = $input->param('amount'); + writeoff($borrowernumber, $accountno, $itemno, $account_type, $amount); +} + my @names = $input->param; -my %inp; my $check = 0; + +## Create a structure for ( my $i = 0 ; $i < @names ; $i++ ) { my $temp = $input->param( $names[$i] ); - if ( $temp eq 'wo' ) { - $inp{ $names[$i] } = $temp; - $check = 1; - } if ( $temp eq 'yes' ) { # FIXME : using array +4, +5, +6 is dirty. Should use arrays for each accountline - my $amount = $input->param( $names[ $i + 4 ] ); - my $borrowernumber = $input->param( $names[ $i + 5 ] ); + my $amount = $input->param( $names[ $i + 4 ] ); # out + my $borrowerno = $input->param( $names[ $i + 5 ] ); my $accountno = $input->param( $names[ $i + 6 ] ); - makepayment( $borrowernumber, $accountno, $amount, $user, $branch ); + makepayment( $borrowerno, $accountno, $amount, $user, $branch ); $check = 2; } } -my $total = $input->param('total') || ''; -if ( $check == 0 ) { - if ( $total ne '' ) { - recordpayment( $borrowernumber, $total ); + +for ( @names ) { + if (/^pay_indiv_(\d+)$/) { + my $line_no = $1; + redirect_to_paycollect('pay_individual', $line_no); + } + if (/^wo_indiv_(\d+)$/) { + my $line_no = $1; + redirect_to_paycollect('writeoff_individual', $line_no); } +} - my ( $total, $accts, $numaccts) = GetMemberAccountRecords( $borrowernumber ); - - my @allfile; - my @notify = NumberNotifyId($borrowernumber); - - my $numberofnotify = scalar(@notify); - for ( my $j = 0 ; $j < scalar(@notify) ; $j++ ) { - my @loop_pay; - my ( $total , $accts, $numaccts) = - GetBorNotifyAcctRecord( $borrowernumber, $notify[$j] ); - for ( my $i = 0 ; $i < $numaccts ; $i++ ) { - my %line; - if ( $accts->[$i]{'amountoutstanding'} != 0 ) { - $accts->[$i]{'amount'} += 0.00; - $accts->[$i]{'amountoutstanding'} += 0.00; - $line{i} = $j . "" . $i; - $line{itemnumber} = $accts->[$i]{'itemnumber'}; - $line{accounttype} = $accts->[$i]{'accounttype'}; - $line{amount} = sprintf( "%.2f", $accts->[$i]{'amount'} ); - $line{amountoutstanding} = - sprintf( "%.2f", $accts->[$i]{'amountoutstanding'} ); - $line{borrowernumber} = $borrowernumber; - $line{accountno} = $accts->[$i]{'accountno'}; - $line{description} = $accts->[$i]{'description'}; - $line{title} = $accts->[$i]{'title'}; - $line{notify_id} = $accts->[$i]{'notify_id'}; - $line{notify_level} = $accts->[$i]{'notify_level'}; - $line{net_balance} = 1 if($accts->[$i]{'amountoutstanding'} > 0); # you can't pay a credit. - push( @loop_pay, \%line ); - } +if ( $check == 0 ) { # fetch and display accounts + add_accounts_to_template($borrowernumber); + + output_html_with_http_headers $input, $cookie, $template->output; + +}else { + + my %inputs; + my @name = $input->param; + for my $name (@name) { + my $test = $input->param( $name ); + if ($test eq 'wo' ) { + my $temp = $name; + $temp=~s/payfine//; + $inputs{ $name } = $temp; } + } + + while ( my ( $key, $value ) = each %inputs ) { - my $totalnotify = AmountNotify( $notify[$j], $borrowernumber ); - ( $totalnotify = '0' ) if ( $totalnotify =~ /^0.00/ ); - push @allfile, - { - 'loop_pay' => \@loop_pay, - 'notify' => $notify[$j], - 'total' => sprintf( "%.2f",$totalnotify), - - }; + my $accounttype = $input->param("accounttype$value"); + my $borrower_number = $input->param("borrowernumber$value"); + my $itemno = $input->param("itemnumber$value"); + my $amount = $input->param("amount$value"); + my $accountno = $input->param("accountno$value"); + writeoff( $borrower_number, $accountno, $itemno, $accounttype, $amount ); } - -if ( $data->{'category_type'} eq 'C') { - my ( $catcodes, $labels ) = GetborCatFromCatType( 'A', 'WHERE category_type = ?' ); - my $cnt = scalar(@$catcodes); - $template->param( 'CATCODE_MULTI' => 1) if $cnt > 1; - $template->param( 'catcode' => $catcodes->[0]) if $cnt == 1; + $borrowernumber = $input->param('borrowernumber'); + print $input->redirect( + "/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber"); +} + +sub writeoff { + my ( $b_number, $accountnum, $itemnum, $accounttype, $amount ) = @_; + my $usr = $input->remote_user; + my $dbh = C4::Context->dbh; + $itemnum ||= undef; # if no item is attached to fine, make sure to store it as a NULL + + my $update = + 'Update accountlines set amountoutstanding=0 ' . + q|where (accounttype='Res' OR accounttype='FU' OR accounttype ='IP' OR accounttype='CH' OR accounttype='N' | . + q|OR accounttype='F' OR accounttype='A' OR accounttype='M' OR accounttype='L' OR accounttype='RE' | . + q|OR accounttype='RL') and accountno=? and borrowernumber=?|; + $dbh->do($update, undef, $accountnum, $b_number ); + + my $account = + $dbh->selectall_arrayref('select max(accountno) as max_accountno from accountlines'); + my $max = 1 + $account->[0]->[0]; + my $insert = q{insert into accountlines (borrowernumber,accountno,itemnumber,date,amount,description,accounttype)} + . q{values (?,?,?,now(),?,'Writeoff','W')}; + $dbh->do($insert, undef, $b_number, $max, $itemnum, $amount ); + + UpdateStats( $branch, 'writeoff', $amount, q{}, q{}, q{}, $b_number ); + + return; } - -$template->param( adultborrower => 1 ) if ( $data->{'category_type'} eq 'A' ); -my ($picture, $dberror) = GetPatronImage($data->{'cardnumber'}); -$template->param( picture => 1 ) if $picture; - + +sub add_accounts_to_template { + my $b_number = shift; + + my ( $total, $accts, $numaccts); + ( $total, $accts, $numaccts) = GetMemberAccountRecords( $b_number ); + + + my $allfile = []; + my @notify = NumberNotifyId($b_number); + + my $line_id = 0; + for my $n (@notify) { + my $pay_loop = []; + my ($acct_total, $acct_accts, $acct_numaccts) = + GetBorNotifyAcctRecord( $b_number, $n ); + if (!$acct_numaccts) { + next; + } + for my $acct ( @{$acct_accts} ) { + if ( $acct->{amountoutstanding} != 0 ) { + $acct->{amount} += 0.00; + $acct->{amountoutstanding} += 0.00; + my $line = { + i => "_$line_id", + itemnumber => $acct->{itemnumber}, + accounttype => $acct->{accounttype}, + amount => sprintf('%.2f', $acct->{amount}), + amountoutstanding => sprintf('%.2f', $acct->{amountoutstanding}), + borrowernumber => $b_number, + accountno => $acct->{accountno}, + description => $acct->{description}, + title => $acct->{title}, + notify_id => $acct->{notify_id}, + notify_level => $acct->{notify_level}, + }; + if ($acct->{amountoutstanding} > 0 ) { + $line->{net_balance} = 1; + } + push @{ $pay_loop}, $line; + ++$line_id; + } + } + my $totalnotify = AmountNotify( $n, $b_number ); + if (!$totalnotify || $totalnotify=~/^0.00/ ) { + $totalnotify = '0'; + } + push @{$allfile}, { + loop_pay => $pay_loop, + notify => $n, + total => sprintf( '%.2f', $totalnotify), + }; + } + + if ( $data->{'category_type'} eq 'C') { + my ( $catcodes, $labels ) = GetborCatFromCatType( 'A', 'WHERE category_type = ?' ); + my $cnt = scalar @{$catcodes}; + if ($cnt > 1) { + $template->param( 'CATCODE_MULTI' => 1); + } elsif ($cnt == 1) { + $template->param( 'catcode' => $catcodes->[0]); + } + } elsif ($data->{'category_type'} eq 'A') { + $template->param( adultborrower => 1 ); + } + + my ($picture, $dberror) = GetPatronImage($data->{'cardnumber'}); + if ($picture ) { + $template->param( picture => 1 ); + } + $template->param( - allfile => \@allfile, + allfile => $allfile, firstname => $data->{'firstname'}, surname => $data->{'surname'}, - borrowernumber => $borrowernumber, - cardnumber => $data->{'cardnumber'}, - categorycode => $data->{'categorycode'}, - category_type => $data->{'category_type'}, - categoryname => $data->{'description'}, - address => $data->{'address'}, - address2 => $data->{'address2'}, - city => $data->{'city'}, - zipcode => $data->{'zipcode'}, - country => $data->{'country'}, - phone => $data->{'phone'}, - email => $data->{'email'}, - branchcode => $data->{'branchcode'}, - branchname => GetBranchName($data->{'branchcode'}), - is_child => ($data->{'category_type'} eq 'C'), - total => sprintf( "%.2f", $total ) + borrowernumber => $b_number, + cardnumber => $data->{'cardnumber'}, + categorycode => $data->{'categorycode'}, + category_type => $data->{'category_type'}, + categoryname => $data->{'description'}, + address => $data->{'address'}, + address2 => $data->{'address2'}, + city => $data->{'city'}, + zipcode => $data->{'zipcode'}, + phone => $data->{'phone'}, + email => $data->{'email'}, + branchcode => $data->{'branchcode'}, + branchname => GetBranchName($data->{'branchcode'}), + is_child => ($data->{'category_type'} eq 'C'), + total => sprintf '%.2f', $total ); - output_html_with_http_headers $input, $cookie, $template->output; + return; +} +sub get_for_redirect { + my ($name, $name_in, $money) = @_; + my $s = q{&} . $name . q{=}; + my $value = $input->param($name_in); + if (!defined $value) { + $value = ($money == 1) ? 0 : q{}; + } + if ($money) { + $s .= sprintf '%.2f', $value; + } else { + $s .= $value; + } + return $s; } -else { - my %inp; +sub redirect_to_paycollect { + my ($action, $line_no) = @_; + my $redirect = "/cgi-bin/koha/members/paycollect.pl?borrowernumber=$borrowernumber"; + $redirect .= q{&}; + $redirect .= "$action=1"; + $redirect .= get_for_redirect('accounttype',"accounttype_$line_no",0); + $redirect .= get_for_redirect('amount',"amount_$line_no",1); + $redirect .= get_for_redirect('amountoutstanding',"out_$line_no",1); + $redirect .= get_for_redirect('accountno',"accountno_$line_no",0); + $redirect .= get_for_redirect('description',"description_$line_no",0); + $redirect .= get_for_redirect('title',"title_$line_no",0); + $redirect .= get_for_redirect('itemnumber',"itemnumber_$line_no",0); + $redirect .= get_for_redirect('notify_id',"notify_id_$line_no",0); + $redirect .= get_for_redirect('notify_level',"notify_level_$line_no",0); + $redirect .= '&remote_user='; + $redirect .= $user; + return print $input->redirect( $redirect ); +} +sub writeoff_all { + my @wo_lines; my @name = $input->param; - for ( my $i = 0 ; $i < @name ; $i++ ) { - my $test = $input->param( $name[$i] ); - if ( $test eq 'wo' ) { - my $temp = $name[$i]; - $temp =~ s/payfine//; - $inp{ $name[$i] } = $temp; + for (@name) { + if (/^line_id_\d+$/) { + push @wo_lines, $input->param($_); } } - my $borrowernumber; - while ( my ( $key, $value ) = each %inp ) { - - my $accounttype = $input->param("accounttype$value"); - $borrowernumber = $input->param("borrowernumber$value"); - my $itemno = $input->param("itemnumber$value"); - my $amount = $input->param("amount$value"); - my $accountno = $input->param("accountno$value"); - writeoff( $borrowernumber, $accountno, $itemno, $accounttype, $amount ); + for my $value (@wo_lines) { + my $accounttype = $input->param("accounttype$value"); + my $borrowernum = $input->param("borrowernumber$value"); + my $itemno = $input->param("itemnumber$value"); + my $amount = $input->param("amount$value"); + my $accountno = $input->param("accountno$value"); + writeoff( $borrowernum, $accountno, $itemno, $accounttype, $amount ); } $borrowernumber = $input->param('borrowernumber'); print $input->redirect( "/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber"); } - -sub writeoff { - my ( $borrowernumber, $accountnum, $itemnum, $accounttype, $amount ) = @_; - my $user = $input->remote_user; - my $dbh = C4::Context->dbh; - undef $itemnum unless $itemnum; # if no item is attached to fine, make sure to store it as a NULL - my $sth = - $dbh->prepare( -"Update accountlines set amountoutstanding=0 where accountno=? and borrowernumber=?" - ); - $sth->execute( $accountnum, $borrowernumber ); - $sth->finish; - $sth = $dbh->prepare("select max(accountno) from accountlines"); - $sth->execute; - my $account = $sth->fetchrow_hashref; - $sth->finish; - $account->{'max(accountno)'}++; - $sth = $dbh->prepare( -"insert into accountlines (borrowernumber,accountno,itemnumber,date,amount,description,accounttype) - values (?,?,?,now(),?,'Writeoff','W')" - ); - $sth->execute( $borrowernumber, $account->{'max(accountno)'}, - $itemnum, $amount ); - $sth->finish; - UpdateStats( $branch, 'writeoff', $amount, '', '', '', - $borrowernumber ); -} diff --git a/members/paycollect.pl b/members/paycollect.pl new file mode 100755 index 0000000..58096e3 --- /dev/null +++ b/members/paycollect.pl @@ -0,0 +1,188 @@ +#!/usr/bin/perl +# Copyright 2009,2010 PTFS Inc. +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Context; +use C4::Auth; +use C4::Output; +use CGI; +use C4::Members; +use C4::Accounts; +use C4::Koha; +use C4::Branch; + +my $input = CGI->new(); + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => 'members/paycollect.tmpl', + query => $input, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { borrowers => 1, updatecharges => 1 }, + debug => 1, + } +); + +# get borrower details +my $borrowernumber = $input->param('borrowernumber'); +my $borrower = GetMember( $borrowernumber, 'borrowernumber' ); +my $user = $input->remote_user; + +# get account details +my $branch = GetBranch( $input, GetBranches() ); + +my ( $total_due, $accts, $numaccts ) = GetMemberAccountRecords($borrowernumber); +my $total_paid = $input->param('paid'); + +my $individual = $input->param('pay_individual'); +my $writeoff = $input->param('writeoff_individual'); +my $select_lines = $input->param('selected'); +my $select = $input->param('selected_accts'); +my $accountno; + +if ( $individual || $writeoff ) { + if ($individual) { + $template->param( pay_individual => 1 ); + } + elsif ($writeoff) { + $template->param( writeoff_individual => 1 ); + } + my $accounttype = $input->param('accounttype'); + my $amount = $input->param('amount'); + my $amountoutstanding = $input->param('amountoutstanding'); + $accountno = $input->param('accountno'); + my $description = $input->param('description'); + my $title = $input->param('title'); + my $notify_id = $input->param('notify_id'); + my $notify_level = $input->param('notify_level'); + $total_due = $amountoutstanding; + $template->param( + accounttype => $accounttype, + accountno => $accountno, + amount => $amount, + amountoutstanding => $amountoutstanding, + title => $title, + description => $description, + notify_id => $notify_id, + notify_level => $notify_level, + ); +} +elsif ($select_lines) { + $total_due = $input->param('amt'); + $template->param( + selected_accts => $select_lines, + amt => $total_due + ); +} + +if ( $total_paid and $total_paid ne '0.00' ) { + if ( $total_paid < 0 or $total_paid > $total_due ) { + $template->param( + error => "You must pay a value less than or equal to $total_due" ); + } + else { + if ($individual) { + if ( $total_paid == $total_due ) { + makepayment( $borrowernumber, $accountno, $total_paid, $user, + $branch ); + } + else { + makepartialpayment( $borrowernumber, $accountno, $total_paid, + $user, $branch ); + } + print $input->redirect( + "/cgi-bin/koha/members/pay.pl?borrowernumber=$borrowernumber"); + } + else { + if ($select) { + if ( $select =~ /^([\d,]*).+/ ) { + $select = $1; # ensure passing no junk + } + my @acc = split /,/, $select; + recordpayment_selectaccts( $borrowernumber, $total_paid, + \@acc ); + } + else { + recordpayment( $borrowernumber, $total_paid ); + } + +# recordpayment does not return success or failure so lets redisplay the boraccount + + print $input->redirect( +"/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber" + ); + } + } +} +else { + $total_paid = '0.00'; #TODO not right with pay_individual +} + +get_borrower_photo($borrower); +my $is_child = ( $borrower->{category_type} && $borrower->{category_type} eq 'C' ); + +$template->param( + firstname => $borrower->{firstname}, + surname => $borrower->{surname}, + borrowernumber => $borrowernumber, + cardnumber => $borrower->{cardnumber}, + categorycode => $borrower->{categorycode}, + category_type => $borrower->{category_type}, + categoryname => $borrower->{description}, + address => $borrower->{address}, + address2 => $borrower->{address2}, + city => $borrower->{city}, + zipcode => $borrower->{zipcode}, + phone => $borrower->{phone}, + email => $borrower->{email}, + branchcode => $borrower->{branchcode}, + branchname => GetBranchName( $borrower->{branchcode} ), + is_child => $is_child, + total => sprintf( '%.2f', $total_due ), +); + +output_html_with_http_headers $input, $cookie, $template->output; + +sub get_borrower_photo { + my $borr = shift; + + if ($borr->{category_type}) { + if ( $borr->{category_type} eq 'C' ) { + my ( $catcodes, $labels ) = + GetborCatFromCatType( 'A', 'WHERE category_type = ?' ); + my $num_catcodes = scalar @{$catcodes}; + if ( $num_catcodes == 1 ) { + $template->param( 'catcode' => $catcodes->[0] ); + } + elsif ( $num_catcodes > 1 ) { + $template->param( 'CATCODE_MULTI' => 1 ); + } + } + + if ( $borr->{'category_type'} eq 'A' ) { + $template->param( adultborrower => 1 ); + } + } + my ( $picture, undef ) = GetPatronImage( $borr->{'cardnumber'} ); + if ($picture) { + $template->param( picture => 1 ); + } + return; +} -- 1.6.6.1