[Koha-patches] [PATCH] Bug 3498 Allow Partial Payment of Fines

Liz Rea lrea at nekls.org
Mon Sep 12 17:03:35 CEST 2011


From: Colin Campbell <colin.campbell at ptfs-europe.com>

Allow partial payment of outstanding fines
against either individual fine entries or as a lump payment

Sponsered by East Brunswick Public Library, East Brunswick, NJ, USA

NB: Adds a version of the include circ-menu.inc as circ-menu.tt
this has the same functionality as the old include but does not
require all the borrowers attributes to be passed as global
scoped variables

Signed-off-by: Liz Rea <lrea at nekls.org>

Bug 3498 - Documentation update to explain what every button does.

Help file updated to the following:
Pay and Writeoff Fines

Each line item can be paid in full, partially paid, or written off.
Pay a fine in full

    Click "Pay" next to the fine you want to pay in full
    The full amount of the fine will be populated for you in the "Collect From Patron" box
    Click "Confirm"
    The fine will be removed from outstanding fines, and displayed as fully paid.

Pay a partial fine

    Click "Pay" next to the fine you want to partially pay
    Enter the amount you are collecting from the patron in the "Collect From Patron" box
    Click "Confirm"
    The fine will be updated to show the original Amount, and the current Amount Outstanding

Writeoff a single fine

    Click "Writeoff" next to the fine you wish to writeoff.
    The fine will be removed from outstanding fines, and displayed as fully paid.

Pay an amount towards all fines

    Click the "Pay Amount" button
    Enter the amount you are collecting from the patron in "Collect from Patron." The sum of all fines is shown in "Total Amount Outstanding"
    Click "Confirm"
    The fine totals will be updated with the payment applied to oldest fines first.

Writeoff All fines

    Click the "Writeoff All" button
    All fines will be removed from outstanding fines, and displayed as written off.

Pay Selected fines

    Check the selection boxes next to the fines you wish to pay, click "Pay Selected"
    Enter an amount to pay towards the fines.
    Click "Confirm"
    The fine totals will be updated with the payment applied to the oldest selected fines first.

Bug 3498 - adding parens to TT IF Statements for style

pay.tt

Bug 3498 - Add parens to TT IF statements for style

paycollect.tt
---
 C4/Accounts.pm                                     |  113 ++++++-
 .../intranet-tmpl/prog/en/includes/circ-menu.tt    |   73 ++++
 .../prog/en/modules/help/members/pay.tt            |   51 +++-
 .../intranet-tmpl/prog/en/modules/members/pay.tt   |  102 +++---
 .../prog/en/modules/members/paycollect.tt          |  227 ++++++++++++
 members/pay.pl                                     |  361 +++++++++++---------
 members/paycollect.pl                              |  171 +++++++++
 7 files changed, 878 insertions(+), 220 deletions(-)
 create mode 100644 koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt
 create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt
 create mode 100755 members/paycollect.pl

diff --git a/C4/Accounts.pm b/C4/Accounts.pm
index eea142c..2352e9e 100644
--- a/C4/Accounts.pm
+++ b/C4/Accounts.pm
@@ -38,7 +38,9 @@ BEGIN {
 		&getnextacctno &reconcileaccount &getcharges &ModNote &getcredits
 		&getrefunds &chargelostitem
 		&ReversePayment
-	); # removed &fixaccounts
+        makepartialpayment
+        recordpayment_selectaccts
+	);
 }
 
 =head1 NAME
@@ -369,7 +371,6 @@ sub manualinvoice {
     my $dbh      = C4::Context->dbh;
     my $notifyid = 0;
     my $insert;
-    $itemnum =~ s/ //g;
     my $accountno  = getnextacctno($borrowernumber);
     my $amountleft = $amount;
 
@@ -413,12 +414,12 @@ sub manualinvoice {
         $notifyid = 1;
     }
 
-    if ( $itemnum ne '' ) {
-        $desc .= " " . $itemnum;
+    if ( $itemnum ) {
+        $desc .= ' ' . $itemnum;
         my $sth = $dbh->prepare(
-            "INSERT INTO  accountlines
+            'INSERT INTO  accountlines
                         (borrowernumber, accountno, date, amount, description, accounttype, amountoutstanding, itemnumber,notify_id, note, manager_id)
-        VALUES (?, ?, now(), ?,?, ?,?,?,?,?,?)");
+        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
@@ -686,6 +687,106 @@ sub ReversePayment {
   }
 }
 
+=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;
+}
+
+# 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;
+}
+
+
+
 END { }    # module clean-up code here (global destructor)
 
 1;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt
new file mode 100644
index 0000000..39be1be
--- /dev/null
+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.tt
@@ -0,0 +1,73 @@
+[%# duplicates circ-menu.inc but assumes all borrower attributes are in a borrower variable rather than
+in the global namespace %]
+[% IF borrower %]
+<div class="patroninfo"><h5>[% borrower.firstname %] [% borrower.surname %] ([% borrower.cardnumber %])</h5>
+<!--[if IE 6]>
+<style type="tex/css">img { width: expression(this.width > 140 ? 140: true);
+}</style>
+<![endif]-->
+<ul>
+[% IF ( patronimages ) %]
+[% IF borrower.has_picture %]
+<li><img src="/cgi-bin/koha/members/patronimage.pl?crdnum=[% borrower.cardnumber %]" id="patronimage" alt="[% borrower.firstname %] [% borrower.surname %] ([% borrower.cardnumber %])" border="0" style="max-width : 140px; margin: .3em 0 .3em .3em; padding: .2em; border: 1px solid #CCCCCC; width:auto !important; width:130px;" /></li>
+[% ELSE %]
+<li><img src="/intranet-tmpl/prog/img/patron-blank.png" alt="[% borrower.firstname %] [% borrower.surname %] ([% borrower.cardnumber %])" border="0" style="margin: .3em 0 .3em .3em; padding: .2em; border: 1px solid #CCCCCC;" /></li>
+[% END %]
+[% END %]
+    <li>[% IF borrower.address %]
+            [% borrower.address %]
+    [% ELSE %]
+            <span class="empty">No address stored.</span>
+    [% END %]</li>
+    [% IF borrower.address2 %]
+        <li>[% borrower.address2 %]</li>
+    [% END %]<li>
+    [% IF borrower.city %]
+            [% borrower.city %][% IF borrower.state %], [% borrower.state %][% END %]
+	    [% borrower.zipcode %][% IF ( borrower.country ) %], [% borrower.country %][% END %]
+    [% ELSE %]
+        <span class="empty">No city stored.</span>
+    [% END %]</li>
+    <li>[% IF borrower.phone %]
+        [% borrower.phone %]
+    [% ELSE %]
+        [% IF borrower.mobile %]
+            [% borrower.mobile %]
+        [% ELSE %]
+            [% IF borrower.phonepro %]
+                [% borrower.phonepro %]
+            [% ELSE %]
+                <span class="empty">No phone stored.</span>
+            [% END %]
+        [% END %]
+    [% END %]</li>
+    [% IF borrower.email %]
+        <li class="email"> <a href="mailto:[% borrower.email %]" title="[% borrower.email %]">[% borrower.email %]</a></li>
+    [% ELSE %]
+        [% IF borrower.emailpro %]
+            <li class="email"> <a href="mailto:[% borrower.emailpro %]" title="[% borrower.emailpro %]">[% borrower.emailpro %]</a></li>
+        [% ELSE %]
+            <li> <span class="empty">No email stored.</span>    </li>
+        [% END %]
+    [% END %]
+    <li>Category: [% borrower.description %] ([% borrower.categorycode %])</li>
+    <li>Home Library: [% IF ( borrower.branchname ) %][% borrower.branchname %][% ELSE %][% borrower.branch %][% END %]</li>
+</ul></div>
+<div id="menu">
+<ul>
+	[% IF ( circview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% borrower.borrowernumber %]">Check Out</a></li>
+	[% IF ( CAN_user_borrowers ) %]
+	[% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrower.borrowernumber %]">Details</a></li>
+	[% END %]
+	 [% IF ( CAN_user_updatecharges ) %]
+	[% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Fines</a></li>
+	[% END %]
+	[% IF ( intranetreadinghistory ) %][% IF ( readingrecordview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/readingrec.pl?borrowernumber=[% borrower.borrowernumber %]">Circulation History</a></li>[% END %]
+	[% IF ( CAN_user_parameters ) %][% IF ( logview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/tools/viewlog.pl?do_it=1&amp;modules=MEMBERS&amp;modules=circulation&amp;object=[% borrower.borrowernumber %]&amp;src=circ">Modification Log</a></li>[% END %]
+    [% IF ( EnhancedMessagingPreferences ) %]
+    [% IF ( messagingview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/messaging.pl?borrowernumber=[% borrower.borrowernumber %]">Messaging</a></li>
+    [% END %]
+    [% IF ( sentnotices ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/notices.pl?borrowernumber=[% borrower.borrowernumber %]">Notices</a></li>
+</ul></div>
+[% END %]
+
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/help/members/pay.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/help/members/pay.tt
index f8eabfa..e0dbfd0 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/help/members/pay.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/help/members/pay.tt
@@ -1,18 +1,51 @@
 [% INCLUDE 'help-top.inc' %]
 
-<h1>Pay/Reverse Fines</h1>
+<h1>Pay and Writeoff Fines</h1>
 
-<p>Each line item can be paid in full (or written off) using the 'Pay Fines' tab.</p>
+<p>Each line item can be paid in full, partially paid, or written off.</p>
 
+<h4>Pay a fine in full</h4>
 <ul>
-	<li>Choose the payment type (Unpaid, Paid, Writeoff) from the pull down menu</li>
-	<li>Click 'Make Payment'</li>
-	<li>A line item will be added to the account information showing the fee paid in full (or written off)</li>
-	<li>If you accidentally mark and item as paid, you can reverse that line item by clicking 'Reverse' to the right of the line
+	<li>Click "Pay" next to the fine you want to pay in full</li>
+	<li>The full amount of the fine will be populated for you in the "Collect From Patron" box</li>
+	<li>Click "Confirm" </li>
+	<li>The fine will be removed from outstanding fines, and displayed as fully paid.</li>
+</ul>
+
+<h4>Pay a partial fine</h4>
+<ul>
+	<li>Click "Pay" next to the fine you want to partially pay</li>
+	<li>Enter the amount you are collecting from the patron in the "Collect From Patron" box</li>
+	<li>Click "Confirm" </li>
+	<li>The fine will be updated to show the original Amount, and the current Amount Outstanding</li>
+</ul>
+
+<h4>Writeoff a single fine</h4>
+<ul>
+	<li>Click "Writeoff" next to the fine you wish to writeoff.</li>
+	<li>The fine will be removed from outstanding fines, and displayed as fully paid.</li>
+</ul>
+
+<h4>Pay an amount towards all fines</h4>
 <ul>
-	<li>Once clicked a new line item will be added to the account, showing the payment as reversed</li>
+	<li>Click the "Pay Amount" button</li>
+	<li>Enter the amount you are collecting from the patron in "Collect from Patron." The sum of all fines is shown in "Total Amount Outstanding"</li>
+	<li>Click "Confirm"</li>
+	<li>The fine totals will be updated with the payment applied to oldest fines first.</li>
 </ul>
-</li>
+
+<h4>Writeoff All fines</h4>
+<ul>
+        <li>Click the "Writeoff All" button</li>
+        <li>All fines will be removed from outstanding fines, and displayed as written off.</li>
+</ul> 
+
+<h4>Pay Selected fines</h4>
+<ul>
+	<li>Check the selection boxes next to the fines you wish to pay, click "Pay Selected"</li>
+	<li>Enter an amount to pay towards the fines.</li>
+	<li>Click "Confirm"</li>
+	<li>The fine totals will be updated with the payment applied to the oldest selected fines first.</li>
 </ul>
 
-[% INCLUDE 'help-bottom.inc' %]
\ No newline at end of file
+[% INCLUDE 'help-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt
index ddc3d41..6dfd8f9 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/pay.tt
@@ -1,12 +1,12 @@
 [% INCLUDE 'doc-head-open.inc' %]
-<title>Koha &rsaquo; Patrons &rsaquo; Pay Fines for  [% firstname %] [% surname %]</title>
+<title>Koha &rsaquo; Patrons &rsaquo; Pay Fines for  [% borrower.firstname %] [% borrower.surname %]</title>
 [% INCLUDE 'doc-head-close.inc' %]
 </head>
 <body>
 [% INCLUDE 'header.inc' %]
 [% INCLUDE 'patron-search.inc' %]
 
-<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>  &rsaquo; Pay Fines for [% firstname %] [% surname %]</div>
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>  &rsaquo; Pay Fines for [% borrower.firstname %] [% borrower.surname %]</div>
 
 <div id="doc3" class="yui-t2">
    
@@ -18,85 +18,91 @@
 <!-- The manual invoice and credit buttons -->
 <div class="toptabs">
 <ul class="ui-tabs-nav">
-	<li><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Account</a></li>
-	<li class="ui-tabs-selected"><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrowernumber %]" >Pay fines</a></li>
-	<li><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrowernumber %]" >Create Manual Invoice</a></li>
-	<li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrowernumber %]" >Create Manual Credit</a></li>
+	<li><a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Account</a></li>
+	<li class="ui-tabs-selected"><a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]" >Pay fines</a></li>
+	<li><a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrower.borrowernumber %]" >Create Manual Invoice</a></li>
+	<li><a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create Manual Credit</a></li>
 </ul>
 <div class="tabs-container">
 
-[% IF ( allfile ) %]<form action="/cgi-bin/koha/members/pay.pl" method="post">
-	<input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrowernumber %]" />
+[% IF ( accounts ) %]
+    <form action="/cgi-bin/koha/members/pay.pl" method="post">
+	<input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrower.borrowernumber %]" />
 
 <table>
 <tr>
 	<th>Fines &amp; Charges</th>
+    <th>Sel</th>
 	<th>Description</th>
-    <th>Note</th>
 	<th>Account Type</th>
 	<th>Notify id</th>
 	<th>Level</th>
 	<th>Amount</th>
 	<th>Amount Outstanding</th>
 </tr>
-	
-[% FOREACH allfil IN allfile %]
-	[% FOREACH loop_pa IN allfil.loop_pay %]
+
+[% FOREACH account_grp IN accounts %]
+    [% FOREACH line IN account_grp.accountlines %]
 <tr>
-	<td>
-	[% IF ( loop_pa.net_balance ) %]
-	<select name="payfine[% loop_pa.i %]">
-	<option value="no">Unpaid</option>
-	<option value="yes">Paid</option>
-	<option value="wo">Writeoff</option>
-	</select>
-	[% END %]
-	<input type="hidden" name="itemnumber[% loop_pa.i %]" value="[% loop_pa.itemnumber %]" />
-	<input type="hidden" name="accounttype[% loop_pa.i %]" value="[% loop_pa.accounttype %]" />
-	<input type="hidden" name="amount[% loop_pa.i %]" value="[% loop_pa.amount %]" />
-	<input type="hidden" name="out[% loop_pa.i %]" value="[% loop_pa.amountoutstanding %]" />
-	<input type="hidden" name="borrowernumber[% loop_pa.i %]" value="[% loop_pa.borrowernumber %]" />
-	<input type="hidden" name="accountno[% loop_pa.i %]" value="[% loop_pa.accountno %]" />
-	<input type="hidden" name="notify_id[% loop_pa.i %]" value="[% loop_pa.notify_id %]" />
-	<input type="hidden" name="notify_level[% loop_pa.i %]" value="[% loop_pa.notify_level %]" />
-	<input type="hidden" name="totals[% loop_pa.i %]" value="[% loop_pa.totals %]" />
-	</td>
-	<td>[% loop_pa.description %] [% loop_pa.title |html %]</td>
     <td>
-        [% IF ( loop_pa.net_balance ) %]
-            <input type="text" name="note[% loop_pa.i %]" value="[% loop_pa.note %]" />
-        [% ELSE %]
-            [% loop_pa.note %]
-        [% END %]
+    [% IF ( line.amountoutstanding > 0 ) %]
+        <input type="submit" name="pay_indiv_[% line.accountno %]" value="Pay" />
+        <input type="submit" name="wo_indiv_[% line.accountno %]" value="Writeoff" />
+    [% END %]
+    <input type="hidden" name="itemnumber[% line.accountno %]" value="[% line.itemnumber %]" />
+    <input type="hidden" name="description[% line.accountno %]" value="[% line.description %]" />
+    <input type="hidden" name="accounttype[% line.accountno %]" value="[% line.accounttype %]" />
+    <input type="hidden" name="amount[% line.accountno %]" value="[% line.amount %]" />
+    <input type="hidden" name="amountoutstanding[% line.accountno %]" value="[% line.amountoutstanding %]" />
+    <input type="hidden" name="borrowernumber[% line.accountno %]" value="[% line.borrowernumber %]" />
+    <input type="hidden" name="accountno[% line.accountno %]" value="[% line.accountno %]" />
+    <input type="hidden" name="notify_id[% line.accountno %]" value="[% line.notify_id %]" />
+    <input type="hidden" name="notify_level[% line.accountno %]" value="[% line.notify_level %]" />
+    <input type="hidden" name="totals[% line.accountno %]" value="[% line.totals %]" />
+    </td>
+    <td>
+    [% IF ( line.amountoutstanding > 0 ) %]
+        <input type="checkbox" checked="checked" name="incl_par_[% line.accountno %]" />
+    [% END %]
     </td>
-	<td>[% loop_pa.accounttype %]</td>
-	<td>[% loop_pa.notify_id %]</td>
-	<td>[% loop_pa.notify_level %]</td>
-	<td class="debit">[% loop_pa.amount %]</td>
-	<td class="debit">[% loop_pa.amountoutstanding %]</td>
+    <td>[% line.description %] [% line.title |html_entity %]</td>
+    <td>[% line.accounttype %]</td>
+    <td>[% line.notify_id %]</td>
+    <td>[% line.notify_level %]</td>
+    <td class="debit">[% line.amount | format('%.2f') %]</td>
+    <td class="debit">[% line.amountoutstanding | format('%.2f') %]</td>
 </tr>
 [% END %]
-[% IF ( allfil.total ) %]
+[% IF ( account_grp.total ) %]
 <tr>
 
-	<td colspan="7">Sub Total</td>
-	<td>[% allfil.total %]</td>
+    <td class="total" colspan="7">Sub Total:</td>
+    <td>[% account_grp.total | format('%.2f') %]</td>
 </tr>
 [% END %]
 [% END %]
 <tr>
-	<td colspan="7">Total Due</td>
-	<td>[% total %]</td>
+    <td class="total" colspan="7">Total Due:</td>
+    <td>[% total | format('%.2f') %]</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=[% borrowernumber %]">Cancel</a></fieldset></form>[% ELSE %]<p>[% firstname %] [% surname %] has no outstanding fines.</p>[% END %]
+<fieldset class="action">
+<input type="submit" name="paycollect"  value="Pay Amount" class="submit" />
+<input type="submit" name="woall"  value="Writeoff All" class="submit" />
+<input type="submit" name="payselected"  value="Pay Selected" class="submit" />
+<a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a>
+</fieldset>
+</form>
+[% ELSE %]
+    <p>[% borrower.firstname %] [% borrower.surname %] has no outstanding fines.</p>
+[% END %]
 </div></div>
 
 </div>
 </div>
 
 <div class="yui-b">
-[% INCLUDE 'circ-menu.inc' %]
+[% INCLUDE 'circ-menu.tt' %]
 </div>
 </div>
 [% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt
new file mode 100644
index 0000000..08ee909
--- /dev/null
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/paycollect.tt
@@ -0,0 +1,227 @@
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Patrons &rsaquo; Collect Fine Payment for  [% borrower.firstname %] [% borrower.surname %]</title>
+[% INCLUDE '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>
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'patron-search.inc' %]
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>  &rsaquo; Pay Fines for [% borrower.firstname %] [% borrower.surname %]</div>
+
+<div id="doc3" class="yui-t2">
+
+<div id="bd">
+<div id="yui-main">
+<div class="yui-b">
+[% INCLUDE '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=[% borrower.borrowernumber %]">Account</a>
+    </li>
+    <li class="ui-tabs-selected">
+    <a href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]" >Pay fines</a>
+    </li>
+    <li>
+    <a href="/cgi-bin/koha/members/maninvoice.pl?borrowernumber=[% borrower.borrowernumber %]" >Create Manual Invoice</a>
+    </li>
+    <li>
+    <a href="/cgi-bin/koha/members/mancredit.pl?borrowernumber=[% borrower.borrowernumber %]" >Create Manual Credit</a>
+    </li>
+</ul>
+<div class="tabs-container">
+[% IF ( error ) %]
+    <div id="error_message" class="dialog alert">
+    [% error %]
+    </div>
+[% END %]
+
+[% IF ( 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="[% borrower.borrowernumber %]" />
+    <input type="hidden" name="pay_individual" id="pay_individual" value="[% pay_individual %]" />
+    <input type="hidden" name="description" id="description" value="[% description %]" />
+    <input type="hidden" name="accounttype" id="accounttype" value="[% accounttype %]" />
+    <input type="hidden" name="notify_id" id="notify_id" value="[% notify_id %]" />
+    <input type="hidden" name="notify_level" id="notify_level" value="[% notify_level %]" />
+    <input type="hidden" name="amount" id="amount" value="[% amount %]" />
+    <input type="hidden" name="amountoutstanding" id="amountoutstanding" value="[% amountoutstanding %]" />
+    <input type="hidden" name="accountno" id="accountno" value="[% accountno %]" />
+    <input type="hidden" name="title" id="title" value="[% 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>
+            [% description %] [% title  %]
+        </td>
+        <td>[% accounttype %]</td>
+        <td>[% notify_id %]</td>
+        <td>[% notify_level %]</td>
+        <td class="debit">[% amount | format('%.2f') %]</td>
+        <td class="debit">[% amountoutstanding | format('%.2f') %]</td>
+    </tr>
+    <tr>
+        <td>Total Amount Payable : </td>
+        <td>[% amountoutstanding | format('%.2f') %]</td>
+        <td colspan="4"></td>
+    </tr>
+    <tr><td colspan="6"> </td></tr>
+    <tr>
+        <td>Collect From Patron: </td>
+        <td>
+            <!-- default to paying all -->
+        <input name="paid" id="paid" value="[% amountoutstanding | format('%.2f') %]" onchange="moneyFormat(document.payindivfine.paid)"/>
+        </td>
+    </tr>
+    <tr><td colspan="6"></td></tr>
+    <tr>
+        <td colspan="6">
+        <input type="submit" name="submitbutton" value="Confirm" />
+        <a class="cancel" href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a>
+        </td>
+    </tr>
+
+    </table>
+    </form>
+[% ELSIF ( writeoff_individual ) %]
+    <form name="woindivfine" action="/cgi-bin/koha/members/pay.pl" method="post" >
+    <input type="hidden" name="borrowernumber" id="borrowernumber" value="[% borrower.borrowernumber %]" />
+    <input type="hidden" name="pay_individual" id="pay_individual" value="[% pay_individual %]" />
+    <input type="hidden" name="description" id="description" value="[% description %]" />
+    <input type="hidden" name="accounttype" id="accounttype" value="[% accounttype %]" />
+    <input type="hidden" name="notify_id" id="notify_id" value="[% notify_id %]" />
+    <input type="hidden" name="notify_level" id="notify_level" value="[% notify_level %]" />
+    <input type="hidden" name="amount" id="amount" value="[% amount %]" />
+    <input type="hidden" name="amountoutstanding" id="amountoutstanding" value="[% amountoutstanding %]" />
+    <input type="hidden" name="accountno" id="accountno" value="[% accountno %]" />
+    <input type="hidden" name="title" id="title" value="[% 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>[% description %] [% title %]</td>
+        <td>[% accounttype %]</td>
+        <td>[% notify_id %]</td>
+        <td>[% notify_level %]</td>
+        <td class="debit">[% amount | format('%.2f') %]</td>
+        <td class="debit">[% amountoutstanding | format('%.2f') %]</td>
+    </tr>
+    <tr><td colspan="6"> </td></tr>
+    <tr><td colspan="6"><strong>Writeoff This Charge?</strong></td></tr>
+    <tr><td> </td></tr>
+    <tr>
+        <td colspan="6">
+        <input type="submit" name="confirm_writeoff" id="confirm_writeoff" value="Confirm" />
+        <a class="cancel" href="/cgi-bin/koha/members/pay.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a>
+        </td>
+    </tr>
+
+    </table>
+    </form>
+[% 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="[% borrower.borrowernumber %]" />
+    <input type="hidden" name="selected_accts" id="selected_accts" value="[% selected_accts %]" />
+    <input type="hidden" name="total" id="total" value="[% total %]" />
+
+    <table>
+    <tr>
+        <td>Total Amount Outstanding : </td>
+        <td class="debit">[% total | format('%.2f') %]</td>
+    </tr>
+    <tr><td colspan="2"> </td></tr>
+    <tr>
+        <td>Collect From Patron: </td>
+        <td>
+        <!-- default to paying all -->
+        <input name="paid" id="paid" value="[% total | format('%.2f') %]" onchange="moneyFormat(document.payfine.paid)"/>
+        </td>
+    </tr>
+    <tr><td></td></tr>
+    <tr>
+        <td colspan="2">
+        <input type="submit" name="submitbutton" value="Confirm" />
+        <a class="cancel" href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrower.borrowernumber %]">Cancel</a>
+        </td>
+    </tr>
+    </table>
+    </form>
+[% END %]
+</div></div>
+</div>
+</div>
+
+<div class="yui-b">
+[% INCLUDE 'circ-menu.tt' %]
+</div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
+
diff --git a/members/pay.pl b/members/pay.pl
index 4ecdcc9..555cfd9 100755
--- a/members/pay.pl
+++ b/members/pay.pl
@@ -2,6 +2,7 @@
 
 # Copyright 2000-2002 Katipo Communications
 # Copyright 2010 BibLibre
+# Copyright 2010,2011 PTFS-Europe Ltd
 #
 # This file is part of Koha.
 #
@@ -18,7 +19,6 @@
 # with Koha; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-
 =head1 pay.pl
 
  written 11/1/2000 by chris at katipo.oc.nz
@@ -38,196 +38,243 @@ use C4::Accounts;
 use C4::Stats;
 use C4::Koha;
 use C4::Overdues;
-use C4::Branch; # GetBranches
+use C4::Branch;
 
-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 $writeoff_sth;
+my $add_writeoff_sth;
+
+my @names = $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 $borrower = GetMember( borrowernumber => $borrowernumber );
 my $user = $input->remote_user;
+$user ||= q{};
 
-# get account details
 my $branches = GetBranches();
-my $branch   = GetBranch( $input, $branches );
+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;
-    }
-    if ( $temp eq 'no'||$temp eq 'yes'||$temp eq 'wo') {
-        my $borrowernumber = $input->param( $names[ $i + 5 ] );
-        my $accountno      = $input->param( $names[ $i + 6 ] );
-        my $note     = $input->param( $names[ $i + 10 ] );
-        ModNote( $borrowernumber, $accountno, $note );
-    }
+my $writeoff_item = $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) {
+    payselected(@names);
 }
 
-my $total = $input->param('total') || '';
-if ( $check == 0 ) {
-    if ( $total ne '' ) {
-        recordpayment( $borrowernumber, $total );
+my $writeoff_all = $input->param('woall');    # writeoff all fines
+if ($writeoff_all) {
+    writeoff_all(@names);
+} elsif ($writeoff_item) {
+    my $accountno    = $input->param('accountno');
+    my $itemno       = $input->param('itemnumber');
+    my $account_type = $input->param('accounttype');
+    my $amount       = $input->param('amount');
+    writeoff( $accountno, $itemno, $account_type, $amount );
+}
+
+for (@names) {
+    if (/^pay_indiv_(\d+)$/) {
+        my $line_no = $1;
+        redirect_to_paycollect( 'pay_individual', $line_no );
+    } elsif (/^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{note}           = $accts->[$i]{'note'};
-                $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 );
-            }
-        }
+add_accounts_to_template();
 
-        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 = ?' );
-   my $cnt = scalar(@$catcodes);
-   $template->param( 'CATCODE_MULTI' => 1) if $cnt > 1;
-   $template->param( 'catcode' =>    $catcodes->[0])  if $cnt == 1;
+output_html_with_http_headers $input, $cookie, $template->output;
+
+sub writeoff {
+    my ( $accountnum, $itemnum, $accounttype, $amount ) = @_;
+
+    # if no item is attached to fine, make sure to store it as a NULL
+    $itemnum ||= undef;
+    get_writeoff_sth();
+    $writeoff_sth->execute( $accountnum, $borrowernumber );
+
+    my $acct = getnextacctno($borrowernumber);
+    $add_writeoff_sth->execute( $borrowernumber, $acct, $itemnum, $amount );
+
+    UpdateStats( $branch, 'writeoff', $amount, q{}, q{}, q{}, $borrowernumber );
+
+    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 ( $total, undef, undef ) = GetMemberAccountRecords($borrowernumber);
+    my $accounts = [];
+    my @notify   = NumberNotifyId($borrowernumber);
+
+    my $notify_groups = [];
+    for my $notify_id (@notify) {
+        my ( $acct_total, $accountlines, undef ) =
+          GetBorNotifyAcctRecord( $borrowernumber, $notify_id );
+        if ( @{$accountlines} ) {
+            my $totalnotify = AmountNotify( $notify_id, $borrowernumber );
+            push @{$accounts},
+              { accountlines => $accountlines,
+                notify       => $notify_id,
+                total        => $totalnotify,
+              };
+        }
+    }
+    borrower_add_additional_fields($borrower);
     $template->param(
-        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'},
-    state => $data->{'state'},
-	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 )
+        accounts => $accounts,
+        borrower => $borrower,
+        total    => $total,
     );
-    output_html_with_http_headers $input, $cookie, $template->output;
+    return;
 
 }
-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;
-        }
+
+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;
     }
-    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 );
+    return $s;
+}
+
+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', "amountoutstanding$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 @params = @_;
+    my @wo_lines = grep { /^accountno\d+$/ } @params;
+    for (@wo_lines) {
+        if (/(\d+)/) {
+            my $value       = $1;
+            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( $accountno, $itemno, $accounttype, $amount );
+        }
     }
+
     $borrowernumber = $input->param('borrowernumber');
     print $input->redirect(
         "/cgi-bin/koha/members/boraccount.pl?borrowernumber=$borrowernumber");
+    return;
 }
 
-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 );
+sub borrower_add_additional_fields {
+    my $b_ref = shift;
+
+# some borrower info is not returned in the standard call despite being assumed
+# in a number of templates. It should not be the business of this script but in lieu of
+# a revised api here it is ...
+    if ( $b_ref->{category_type} eq 'C' ) {
+        my ( $catcodes, $labels ) =
+          GetborCatFromCatType( 'A', 'WHERE category_type = ?' );
+        if ( @{$catcodes} ) {
+            if ( @{$catcodes} > 1 ) {
+                $b_ref->{CATCODE_MULTI} = 1;
+            } elsif ( @{$catcodes} == 1 ) {
+                $b_ref->{catcode} = $catcodes->[0];
+            }
+        }
+    } elsif ( $b_ref->{category_type} eq 'A' ) {
+        $b_ref->{adultborrower} = 1;
+    }
+    my ( $picture, $dberror ) = GetPatronImage( $b_ref->{cardnumber} );
+    if ($picture) {
+        $b_ref->{has_picture} = 1;
+    }
+
+    $b_ref->{branchname} = GetBranchName( $b_ref->{branchcode} );
+    return;
+}
+
+sub payselected {
+    my @params = @_;
+    my $amt    = 0;
+    my @lines_to_pay;
+    foreach (@params) {
+        if (/^incl_par_(\d+)$/) {
+            my $index = $1;
+            push @lines_to_pay, $input->param("accountno$index");
+            $amt += $input->param("amountoutstanding$index");
+        }
+    }
+    $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);
+    return;
+}
+
+sub get_writeoff_sth {
+
+    # lets prepare these statement handles only once
+    if ($writeoff_sth) {
+        return;
+    } else {
+        my $dbh = C4::Context->dbh;
+
+        # Do we need to validate accounttype
+        my $sql = 'Update accountlines set amountoutstanding=0 '
+          . 'WHERE accountno=? and borrowernumber=?';
+        $writeoff_sth = $dbh->prepare($sql);
+        my $insert =
+q{insert into accountlines (borrowernumber,accountno,itemnumber,date,amount,description,accounttype)}
+          . q{values (?,?,?,now(),?,'Writeoff','W')};
+        $add_writeoff_sth = $dbh->prepare($insert);
+    }
+    return;
 }
diff --git a/members/paycollect.pl b/members/paycollect.pl
new file mode 100755
index 0000000..cbddc05
--- /dev/null
+++ b/members/paycollect.pl
@@ -0,0 +1,171 @@
+#!/usr/bin/perl
+# Copyright 2009,2010 PTFS Inc.
+# Copyright 2011 PTFS-Europe Ltd
+#
+# 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 => sprintf( 'You must pay a value less than or equal to %f.2',
+                $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
+}
+
+borrower_add_additional_fields($borrower);
+
+$template->param(
+
+ #borrowenumber  => $borrower->{borrowernumber}, # some templates require global
+    borrowenumber => $borrowernumber,    # some templates require global
+    borrower      => $borrower,
+    total         => $total_due
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;
+
+sub borrower_add_additional_fields {
+    my $b_ref = shift;
+
+# some borrower info is not returned in the standard call despite being assumed
+# in a number of templates. It should not be the business of this script but in lieu of
+# a revised api here it is ...
+    if ( $b_ref->{category_type} eq 'C' ) {
+        my ( $catcodes, $labels ) =
+          GetborCatFromCatType( 'A', 'WHERE category_type = ?' );
+        if ( @{$catcodes} ) {
+            if ( @{$catcodes} > 1 ) {
+                $b_ref->{CATCODE_MULTI} = 1;
+            } elsif ( @{$catcodes} == 1 ) {
+                $b_ref->{catcode} = $catcodes->[0];
+            }
+        }
+    } elsif ( $b_ref->{category_type} eq 'A' ) {
+        $b_ref->{adultborrower} = 1;
+    }
+    my ( $picture, $dberror ) = GetPatronImage( $b_ref->{cardnumber} );
+    if ($picture) {
+        $b_ref->{has_picture} = 1;
+    }
+
+    $b_ref->{branchname} = GetBranchName( $b_ref->{branchcode} );
+    return;
+}
-- 
1.7.2.5



More information about the Koha-patches mailing list