From d3c6a0a7eb0c9ee93b8d64e21a0813d553d5b83b Mon Sep 17 00:00:00 2001
From: Kyle M Hall <kyle@bywatersolutions.com>
Date: Mon, 11 Jul 2016 15:36:54 +0000
Subject: [PATCH] Bug 16899 - Add ability to disallow overpayments

Some SIP services ( such as Comprise ) require that an attempt at
over-paying a patron's account via SIP2 should fail, rather than create
a credit on the account. We should make this a configurable option on a
per-login basis in the SIP2 config file.

Test Plan:
1) Apply this patch
2) Enable the new parameter
   disallow_overpayment="1"
   for the login to be used in this test.
3) Restart your SIP server
4) Create or find a patron with fines
5) Attempt to send a payment via SIP for more than what the
   patron's balance is
6) Note the response indicates a payment failure
7) Attempt to send a payment via SIP for the account balance or
   less
8) Note the response indicates the payment has succeeded
9) Verify in Koha that the payment was processed
---
 C4/SIP/ILS.pm                        |  4 ++--
 C4/SIP/ILS/Transaction/FeePayment.pm | 11 ++++++++++-
 C4/SIP/Sip/MsgType.pm                |  3 ++-
 Koha/Account/Lines.pm                | 10 ++++++++++
 Koha/Patron.pm                       | 17 +++++++++++++++++
 etc/SIPconfig.xml                    |  2 +-
 t/db_dependent/Patron.t              | 23 ++++++++++++++++++++++-
 7 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/C4/SIP/ILS.pm b/C4/SIP/ILS.pm
index 35879af..5d3f189 100644
--- a/C4/SIP/ILS.pm
+++ b/C4/SIP/ILS.pm
@@ -247,7 +247,7 @@ sub end_patron_session {
 }
 
 sub pay_fee {
-    my ($self, $patron_id, $patron_pwd, $fee_amt, $fee_type, $pay_type, $fee_id, $trans_id, $currency, $is_writeoff) = @_;
+    my ($self, $patron_id, $patron_pwd, $fee_amt, $fee_type, $pay_type, $fee_id, $trans_id, $currency, $is_writeoff, $disallow_overpayment ) = @_;
 
     my $trans = C4::SIP::ILS::Transaction::FeePayment->new();
 
@@ -258,7 +258,7 @@ sub pay_fee {
         $trans->screen_msg('Invalid patron barcode.');
         return $trans;
     }
-    my $ok = $trans->pay( $patron->{borrowernumber}, $fee_amt, $pay_type, $fee_id, $is_writeoff );
+    my $ok = $trans->pay( $patron->{borrowernumber}, $fee_amt, $pay_type, $fee_id, $is_writeoff, $disallow_overpayment );
     $trans->ok($ok);
 
     return $trans;
diff --git a/C4/SIP/ILS/Transaction/FeePayment.pm b/C4/SIP/ILS/Transaction/FeePayment.pm
index e2b73cd..7baee6c 100644
--- a/C4/SIP/ILS/Transaction/FeePayment.pm
+++ b/C4/SIP/ILS/Transaction/FeePayment.pm
@@ -21,7 +21,7 @@ use strict;
 # along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 use C4::Accounts qw(recordpayment makepayment WriteOffFee);
-use Koha::Account::Lines;
+use Koha::Patrons;
 use parent qw(C4::SIP::ILS::Transaction);
 
 
@@ -48,9 +48,18 @@ sub pay {
     my $type           = shift;
     my $fee_id         = shift;
     my $is_writeoff    = shift;
+    my $disallow_overpayment = shift;
 
     warn("RECORD:$borrowernumber::$amt");
 
+    if ($disallow_overpayment) {
+        my $patron = Koha::Patrons->find($borrowernumber);
+        return 0 unless $patron;
+
+        my $balance = $patron->account_balance();
+        return 0 if $balance < $amt;
+    }
+
     my $fee = $fee_id ? Koha::Account::Lines->find($fee_id) : undef;
 
     if ($is_writeoff) { # Writeoffs require a fee id to be sent
diff --git a/C4/SIP/Sip/MsgType.pm b/C4/SIP/Sip/MsgType.pm
index 3660aa4..df9957e 100644
--- a/C4/SIP/Sip/MsgType.pm
+++ b/C4/SIP/Sip/MsgType.pm
@@ -1068,6 +1068,7 @@ sub handle_fee_paid {
     my $status;
     my $resp = FEE_PAID_RESP;
 
+    my $disallow_overpayment = $server->{account}->{disallow_overpayment};
     my $payment_type_writeoff = $server->{account}->{payment_type_writeoff};
     my $is_writeoff = $pay_type eq $payment_type_writeoff;
 
@@ -1080,7 +1081,7 @@ sub handle_fee_paid {
 
     $ils->check_inst_id( $inst_id, "handle_fee_paid" );
 
-    $status = $ils->pay_fee( $patron_id, $patron_pwd, $fee_amt, $fee_type, $pay_type, $fee_id, $trans_id, $currency, $is_writeoff );
+    $status = $ils->pay_fee( $patron_id, $patron_pwd, $fee_amt, $fee_type, $pay_type, $fee_id, $trans_id, $currency, $is_writeoff, $disallow_overpayment );
 
     $resp .= ( $status->ok ? 'Y' : 'N' ) . timestamp;
     $resp .= add_field( FID_INST_ID,   $inst_id );
diff --git a/Koha/Account/Lines.pm b/Koha/Account/Lines.pm
index 0e0677c..33e5e22 100644
--- a/Koha/Account/Lines.pm
+++ b/Koha/Account/Lines.pm
@@ -36,6 +36,16 @@ Koha::Account::Lines - Koha Account Line Object set class
 
 =cut
 
+=head3 amount_outstanding
+
+=cut
+
+sub amount_outstanding {
+    my ( $self ) = @_;
+
+    return $self->_resultset()->get_column('amountoutstanding')->sum();
+}
+
 =head3 type
 
 =cut
diff --git a/Koha/Patron.pm b/Koha/Patron.pm
index 42b066b..34bb090 100644
--- a/Koha/Patron.pm
+++ b/Koha/Patron.pm
@@ -24,6 +24,7 @@ use Carp;
 
 use C4::Context;
 use C4::Log;
+use Koha::Account::Lines;
 use Koha::Database;
 use Koha::DateUtils;
 use Koha::Issues;
@@ -44,6 +45,22 @@ Koha::Patron - Koha Patron Object class
 
 =cut
 
+=head3 account_balance
+
+Returns the total amount owed by this patron
+
+=cut
+
+sub account_balance {
+    my ($self) = @_;
+
+    return Koha::Account::Lines->search(
+        {
+            borrowernumber => $self->id
+        }
+    )->amount_outstanding();
+}
+
 =head3 guarantor
 
 Returns a Koha::Patron object for this patron's guarantor
diff --git a/etc/SIPconfig.xml b/etc/SIPconfig.xml
index 96cd1c8..70d802e 100644
--- a/etc/SIPconfig.xml
+++ b/etc/SIPconfig.xml
@@ -44,7 +44,7 @@
   </listeners>
 
   <accounts>
-      <login id="term1"  password="term1" delimiter="|" error-detect="enabled" institution="CPL" encoding="ascii" checked_in_ok="1" payment_type_writeoff="06" />
+      <login id="staff"  password="staff" delimiter="|" error-detect="enabled" institution="CPL" encoding="ascii" checked_in_ok="1" payment_type_writeoff="06" disallow_overpayment="1" />
       <login id="koha"   password="koha"  delimiter="|" error-detect="enabled" institution="kohalibrary" encoding="utf8" />
       <login id="koha2"  password="koha" institution="kohalibrary2" terminator="CR" />
       <login id="lpl-sc" password="1234" institution="LPL" />
diff --git a/t/db_dependent/Patron.t b/t/db_dependent/Patron.t
index 11c57fe..5ea9b6c 100755
--- a/t/db_dependent/Patron.t
+++ b/t/db_dependent/Patron.t
@@ -17,11 +17,12 @@
 
 use Modern::Perl;
 
-use Test::More tests => 13;
+use Test::More tests => 14;
 use Test::Warn;
 
 use C4::Context;
 use Koha::Database;
+use Koha::Account::Line;
 
 BEGIN {
     use_ok('Koha::Object');
@@ -50,6 +51,26 @@ my $borrowernumber = $object->borrowernumber;
 my $patron = $schema->resultset('Borrower')->find( $borrowernumber );
 is( $patron->surname(), "Test Surname", "Object found in database" );
 
+my $accountline_1 = Koha::Account::Line->new(
+    {
+        borrowernumber    => $patron->id,
+        accountno         => 1,
+        amount            => 10.00,
+        amountoutstanding => 5.00,
+    }
+)->store();
+
+my $accountline_2 = Koha::Account::Line->new(
+    {
+        borrowernumber    => $patron->id,
+        accountno         => 2,
+        amount            => 7.00,
+        amountoutstanding => 7.00,
+    }
+)->store();
+
+is( $object->account_balance, '12.000000', "Got correct patron account balance" );
+
 is( $object->is_changed(), 0, "Object is unchanged" );
 $object->surname("Test Surname");
 is( $object->is_changed(), 0, "Object is still unchanged" );
-- 
2.1.4