[Koha-patches] [PATCH] Fines System Updates - Code Cleanup & Additional Features
Kyle M Hall
kyle.m.hall at gmail.com
Wed Mar 17 13:51:24 CET 2010
* Major code cleanup for pay.pl
* Added ability to negotiate fines ( i.e. Change the fine amount )
* Added ability to pay, writeoff, and negotiate partial amounts.
* Moved additional functions from pay.pl to Accounts.pm
---
C4/Accounts.pm | 57 ++++++-
.../intranet-tmpl/prog/en/modules/members/pay.tmpl | 147 ++++++++++++++-
members/pay.pl | 198 +++++++-------------
3 files changed, 263 insertions(+), 139 deletions(-)
diff --git a/C4/Accounts.pm b/C4/Accounts.pm
index bbc6c00..599c67f 100644
--- a/C4/Accounts.pm
+++ b/C4/Accounts.pm
@@ -35,7 +35,7 @@ BEGIN {
@EXPORT = qw(
&recordpayment &makepayment &manualinvoice
&getnextacctno &reconcileaccount &getcharges &getcredits
- &getrefunds &chargelostitem
+ &getrefunds &chargelostitem &writeoff &negotiate
&ReversePayment
); # removed &fixaccounts
}
@@ -170,7 +170,7 @@ sub makepayment {
$dbh->do(
"UPDATE accountlines
- SET amountoutstanding = 0
+ SET amountoutstanding = amountoutstanding - $amount
WHERE borrowernumber = $borrowernumber
AND accountno = $accountno
"
@@ -648,6 +648,59 @@ sub getrefunds {
return (@results);
}
+sub writeoff {
+ my ( $borrowernumber, $accountnum, $itemnum, $accounttype, $amount ) = @_;
+ 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 $query = "UPDATE accountlines SET amountoutstanding = amountoutstanding - $amount WHERE accountno = ? AND borrowernumber = ?";
+ my $sth = $dbh->prepare( $query );
+ $sth->execute( $accountnum, $borrowernumber );
+
+ my $next_accountno = getnextacctno( $borrowernumber );
+
+ $query = "INSERT INTO accountlines
+ ( borrowernumber, accountno, itemnumber, date, amount, description, accounttype )
+ VALUES
+ ( ?, ?, ?, NOW(), ?, 'Writeoff', 'W' )
+ ";
+ $sth = $dbh->prepare( $query );
+ $sth->execute( $borrowernumber, $next_accountno, $itemnum, $amount );
+
+ UpdateStats( C4::Context->userenv->{branch}, 'writeoff', $amount, '', '', '', $borrowernumber );
+}
+
+sub negotiate {
+ my ( $borrowernumber, $accountno, $amount, $itemnumber ) = @_;
+ my $dbh = C4::Context->dbh;
+
+ my $query = "
+ UPDATE
+ accountlines
+ SET
+ amount = amount - ?,
+ description = CONCAT( description, '*' ),
+ amountoutstanding = amountoutstanding - ?,
+ timestamp = NOW()
+ WHERE
+ accountno = ?
+ AND
+ borrowernumber = ?
+ ";
+ my $sth = $dbh->prepare( $query );
+ $sth->execute( $amount, $amount, $accountno, $borrowernumber );
+
+ my $next_accountno = getnextacctno( $borrowernumber );
+
+ $query = "INSERT INTO accountlines
+ ( borrowernumber, accountno, itemnumber, date, amount, description, accounttype )
+ VALUES
+ ( ?, ?, ?, NOW(), ?, 'Negotiated', 'N' )
+ ";
+ $sth = $dbh->prepare( $query );
+ $sth->execute( $borrowernumber, $next_accountno, $itemnumber, $amount );
+}
+
sub ReversePayment {
my ( $borrowernumber, $accountno ) = @_;
my $dbh = C4::Context->dbh;
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..79fab31 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tmpl
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tmpl
@@ -1,6 +1,104 @@
<!-- TMPL_INCLUDE NAME="doc-head-open.inc" -->
<title>Koha › Patrons › Pay Fines for <!-- TMPL_VAR NAME="firstname" --> <!-- TMPL_VAR NAME="surname" --></title>
<!-- TMPL_INCLUDE NAME="doc-head-close.inc" -->
+
+<script type='text/javascript'>
+ function payfineOnChange( id, amount ) {
+ var selectName = "payfine" + id;
+ var inputName = "amount_to_pay" + id;
+
+ var mySelect = document.getElementsByName( selectName )[0];
+ var myInput = document.getElementsByName( inputName )[0];
+
+ if ( mySelect.value == "no" ) {
+ myInput.value = '';
+ } else {
+ if ( myInput.value == '' ) {
+ myInput.value = amount;
+ myInput.select().focus();
+ }
+ }
+ }
+
+ function amountOnChange( id ) {
+ var selectName = "payfine" + id;
+ var inputName = "amount_to_pay" + id;
+
+ var mySelect = document.getElementsByName( selectName )[0];
+ var myInput = document.getElementsByName( inputName )[0];
+
+ if ( myInput.value == '' ) {
+ mySelect.selectedIndex = 0;
+ } else {
+ if ( mySelect.selectedIndex == 0 ) {
+ mySelect.selectedIndex = 1;
+ }
+ }
+ }
+
+ function checkField( fieldname, total ){
+
+ var myInput = document.getElementsByName( fieldname )[0];
+ total = parseFloat( total );
+
+ if ( myInput.value != '' ) {
+ var regExp = /^\d*(\.\d{2})?$/; // This regular express only accepts floating point numbers ex. 5, 5.30, .80, etc...
+ if ( ! regExp.test( myInput.value ) ) {
+ alert("Invalid Amount: " + myInput.value );
+ myInput.focus();
+ myInput.select();
+ return false;
+ }
+
+
+ if ( myInput.value > total ) {
+ if ( confirm("You are trying to make a payment larger then the Amount Outstanding.\n\nAre you sure you want to do this?") ) {
+ return true;
+ } else {
+ myInput.focus();
+ myInput.select();
+ return false;
+ }
+ }
+
+ if ( myInput.value.indexOf('.') < 0 ) {
+ if ( confirm("The amount you've entered has no '.'\n\nAre you sure you want to do this?") ) {
+ return true;
+ } else {
+ myInput.focus();
+ myInput.select();
+
+ return false;
+ }
+ }
+
+ }
+
+ return true;
+ }
+
+ function formatField( myInput ) {
+ if ( myInput.value && !isNaN( myInput.value ) ) {
+ myInput.value = formatAsCurrency( myInput.value );
+ }
+ }
+
+ function formatAsCurrency(number) {
+ number = number.toString().replace(/\$|\,/g,'');
+ if ( isNaN( number ) ) number = "0";
+ number = Math.floor( number * 100 + 0.50000000001 );
+ cents = number % 100;
+ number = Math.floor(number/100).toString();
+
+ if( cents < 10 ) cents = "0" + cents;
+
+ for (var i = 0; i < Math.floor((number.length-(1+i))/3); i++) {
+ number = number.substring( 0, number.length - ( 4 * i + 3 ) ) + ',' + number.substring( number.length - ( 4 * i + 3 ) );
+ }
+ return number + '.' + cents;
+ }
+</script>
+
</head>
<body>
<!-- TMPL_INCLUDE NAME="header.inc" -->
@@ -30,12 +128,13 @@
<table>
<tr>
- <th>Fines & Charges</th>
+ <th>Action</th>
+ <th>Amount</th>
<th>Description</th>
<th>Account Type</th>
<th>Notify id</th>
<th>Level</th>
- <th>Amount</th>
+ <th>Fine Amount</th>
<th>Amount Outstanding</th>
</tr>
@@ -43,13 +142,14 @@
<!-- TMPL_LOOP name="loop_pay" -->
<tr>
<td>
- <!-- TMPL_IF NAME="net_balance" -->
- <select name="payfine<!-- TMPL_VAR name="i" -->">
- <option value="no">Unpaid</option>
- <option value="yes">Paid</option>
- <option value="wo">Writeoff</option>
+
+ <select name="payfine<!-- TMPL_VAR name="i" -->" onchange="payfineOnChange('<!-- TMPL_VAR name="i" -->', '<!-- TMPL_VAR name="amountoutstanding" -->')" >
+ <option value="no">Don't Pay</option>
+ <option value="yes">Pay</option>
+ <option value="wo">Writeoff</option>
+ <option value="ng">Negotiate</option>
</select>
- <!-- /TMPL_IF -->
+
<input type="hidden" name="itemnumber<!-- TMPL_VAR name="i" -->" value="<!-- TMPL_VAR name="itemnumber" -->" />
<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" -->" />
@@ -60,6 +160,16 @@
<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>
+ <input
+ type="text"
+ name="amount_to_pay<!-- TMPL_VAR name="i" -->"
+ size="6"
+ onkeyup="amountOnChange('<!-- TMPL_VAR name="i" -->')"
+ onchange="formatField( this )";
+ onblur="return checkField( 'amount_to_pay<!-- TMPL_VAR name="i" -->', '<!-- TMPL_VAR name="amountoutstanding" -->')"
+ />
+ </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,19 +181,34 @@
<!-- 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 -->
+<fieldset class="action"><input type="submit" name="submit" value="Update Fines & Charges" class="submit" /> <a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=<!-- TMPL_VAR NAME="borrowernumber" -->">Cancel</a></fieldset></form>
+
+<fieldset>
+ <legend>Pay Fines by Amount</legend>
+ <form class="inline" action="pay.pl" method="post" onsubmit="return checkField( 'pay_by_amount', '<!-- TMPL_VAR name="total" -->')">
+ <input type="hidden" name="borrowernumber" value="<!-- TMPL_VAR name="borrowernumber" -->" />
+ <label for="pay_by_amount">Amount to be paid:</label>
+ <input id="pay_by_amount" name="pay_by_amount" type="text" />
+ <input type="submit" name="submit" value="Make Partial Payment" class="submit"/>
+ </form>
+</fieldset>
</div></div>
+<!-- TMPL_ELSE -->
+ <p><!-- TMPL_VAR NAME="firstname" --> <!-- TMPL_VAR NAME="surname" --> has no outstanding fines.</p>
+<!-- /TMPL_IF -->
+
+
</div>
</div>
diff --git a/members/pay.pl b/members/pay.pl
index 5a36bd7..edbe9e8 100755
--- a/members/pay.pl
+++ b/members/pay.pl
@@ -52,86 +52,86 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
}
);
-my $borrowernumber = $input->param('borrowernumber');
-if ( $borrowernumber eq '' ) {
- $borrowernumber = $input->param('borrowernumber0');
-}
+my $borrowernumber = $input->param('borrowernumber') || $input->param('borrowernumber00');
# get borrower details
my $data = GetMember( borrowernumber => $borrowernumber );
-my $user = $input->remote_user;
# get account details
my $branches = GetBranches();
-my $branch = GetBranch( $input, $branches );
-
-my @names = $input->param;
-my %inp;
-my $check = 0;
-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 $accountno = $input->param( $names[ $i + 6 ] );
- makepayment( $borrowernumber, $accountno, $amount, $user, $branch );
- $check = 2;
+my $branch = GetBranch( $input, $branches );
+
+my $i = 0;
+my $index = '00';
+while ( $input->param( "payfine$index") ) {
+warn "Payfine$index: " . $input->param( "payfine$index" );
+ my $payfine = $input->param( "payfine$index" );
+ my $amount = $input->param( "amount$index" );
+ my $accountno = $input->param( "accountno$index" );
+ my $amount_to_pay = $input->param( "amount_to_pay$index" );
+ my $itemnumber = $input->param( "itemnumber$index" );
+ my $accounttype = $input->param( "accounttype$index" );
+ $amount = $amount_to_pay if ( $amount_to_pay );
+
+ if ( $payfine eq 'yes' ) { ## Standard Fine Payment
+ makepayment( $borrowernumber, $accountno, $amount, '', $branch );
+ } elsif ( $payfine eq 'wo' ) { ## Writeoff
+ writeoff( $borrowernumber, $accountno, $itemnumber, $accounttype, $amount );
+ } elsif ( $payfine eq 'ng' ) { ## Negotiate Fine
+ negotiate( $borrowernumber, $accountno, $amount, $itemnumber );
}
+
+ $i++;
+ $index = $i;
+ $index = "0$i" if ( $i < 10 );
}
-my $total = $input->param('total') || '';
-if ( $check == 0 ) {
- if ( $total ne '' ) {
- recordpayment( $borrowernumber, $total );
- }
- 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 );
- }
- }
+## Pay by Amount
+my $total_to_pay = $input->param('pay_by_amount');
+if ( $total_to_pay ) {
+ recordpayment( $borrowernumber, $total_to_pay );
+}
- 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),
-
- };
+## Get Fine Details
+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 );
+ }
}
+
+ 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),
+ };
+}
if ( $data->{'category_type'} eq 'C') {
my ( $catcodes, $labels ) = GetborCatFromCatType( 'A', 'WHERE category_type = ?' );
@@ -144,7 +144,7 @@ $template->param( adultborrower => 1 ) if ( $data->{'category_type'} eq 'A' );
my ($picture, $dberror) = GetPatronImage($data->{'cardnumber'});
$template->param( picture => 1 ) if $picture;
- $template->param(
+$template->param(
allfile => \@allfile,
firstname => $data->{'firstname'},
surname => $data->{'surname'},
@@ -164,60 +164,6 @@ $template->param( picture => 1 ) if $picture;
branchname => GetBranchName($data->{'branchcode'}),
is_child => ($data->{'category_type'} eq 'C'),
total => sprintf( "%.2f", $total )
- );
- output_html_with_http_headers $input, $cookie, $template->output;
-
-}
-else {
-
- my %inp;
- 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;
- }
- }
- 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 );
- }
- $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 );
-}
+output_html_with_http_headers $input, $cookie, $template->output;
--
1.5.6.5
More information about the Koha-patches
mailing list