Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/applicants/payment.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/applicants/payment.py	(revision 15729)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/applicants/payment.py	(revision 15730)
@@ -41,6 +41,10 @@
         return
 
+    @property
+    def net_amt(self):
+        return self.amount_auth - self.provider_amt - self.gateway_amt
+
 NigeriaApplicantOnlinePayment = attrs_to_fields(
-    NigeriaApplicantOnlinePayment, omit=['display_item'])
+    NigeriaApplicantOnlinePayment, omit=['display_item', 'net_amt'])
 
 # Applicant online payments must be importable. So we might need a factory.
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/helpers.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/helpers.py	(revision 15729)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/helpers.py	(revision 15730)
@@ -22,4 +22,6 @@
 from datetime import datetime
 from urllib import urlencode
+from urllib2 import urlopen
+from urlparse import parse_qs
 import httplib
 import hashlib
@@ -193,2 +195,72 @@
     notify(grok.ObjectModifiedEvent(payment))
     return True, msg, log
+
+# Requerying Etranzact Payoutlet payments
+
+# Expected response:
+# RECEIPT_NO=500191030486&PAYMENT_CODE=500854291572447457669&MERCHANT_CODE=700602WDUB
+# &TRANS_AMOUNT=200000.0&TRANS_DATE=2019/10/30
+# 15:13:47&TRANS_DESCR=Test%20Test%20Test-CLEARANCE%20-001-p5723474039401
+# &CUSTOMER_ID=p5723474039401&BANK_CODE=500&BRANCH_CODE=001
+# &SERVICE_ID=p5723474039401&CUSTOMER_NAME=Test%20Test%20Test
+# &CUSTOMER_ADDRESS=ASS-ENG&TELLER_ID=etzbankteller&USERNAME=%20
+# &PASSWORD=%20&BANK_NAME=eTranzact%20Intl%20Plc
+# &BRANCH_NAME=ETRANZACT&CHANNEL_NAME=Bank&PAYMENT_METHOD_NAME=Cash
+# &PAYMENT_CURRENCY=566&TRANS_TYPE=101&TRANS_FEE=0.0
+# &TYPE_NAME=CLEARANCE&LEAD_BANK_CODE=700&LEAD_BANK_NAME=eTranzact%20Intl%20Plc
+# COL1=2018/2019&COL2=Acceptance
+# Fee&COL3=ASS&COL4=ENG&COL5=BARTENL&COL6=400&COL7=ug_ft&COL8=N/A&COL9=11/12345
+# &COL10=damms005@gmail.com&COL11=None&COL12=&COL13=
+
+def query_payoutlet(host, terminal_id, confirmation_number, payment, https):
+    headers={"Content-type": "application/x-www-form-urlencoded",
+             "Accept": "text/plain"}
+    url = "/WebConnectPlus/query.jsp"
+    if https:
+        h = httplib.HTTPSConnection(host)
+    else:
+        h = httplib.HTTPConnection(host)
+    args = {'TERMINAL_ID': terminal_id,
+            'CONFIRMATION_NO': confirmation_number,
+            }
+    h.request('POST', url, urlencode(args), headers)
+    response = h.getresponse()
+    if response.status!=200:
+        return False, 'Connection error (%s, %s)' % (response.status, response.reason), None
+    raw = response.read()
+    # Remove empty lines
+    raw = raw.replace('\r\n','')
+    success = parse_qs(raw)
+    if not success.get('CUSTOMER_ID'):
+        msg = _('Invalid or unsuccessful callback: ${a}',
+            mapping = {'a': raw})
+        log = 'invalid callback for payment %s: %s' % (payment.p_id, raw)
+        payment.p_state = 'failed'
+        return False, msg, log
+    # We expect at least two parameters
+    if len(success) < 2:
+        msg = _('Invalid callback: ${a}', mapping = {'a': raw})
+        log = 'invalid callback for payment %s: %s' % (payment.p_id, raw)
+        payment.p_state = 'failed'
+        return False, msg, log
+    payment.r_code = u'ET'
+    payment.r_desc = u'%s' % success.get('TRANS_DESCR')[0]
+    payment.r_amount_approved = float(success.get('TRANS_AMOUNT')[0])
+    payment.r_card_num = None
+    payment.r_pay_reference = u'%s' % success.get('RECEIPT_NO')[0]
+    if payment.r_amount_approved != payment.amount_auth:
+        msg = _('Wrong amount')
+        log = 'wrong callback for payment %s: %s' % (payment.p_id, raw)
+        payment.p_state = 'failed'
+        return False, msg, log
+    customer_id = success.get('CUSTOMER_ID')[0]
+    if payment.p_id != customer_id:
+        msg = _('Wrong payment id')
+        log = 'wrong callback for payment %s: %s' % (payment.p_id, raw)
+        payment.p_state = 'failed'
+        return False, msg, log
+    log = 'valid callback for payment %s: %s' % (payment.p_id, raw)
+    msg = _('Successful callback received')
+    payment.p_state = 'paid'
+    payment.payment_date = datetime.utcnow()
+    return True, msg, log
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/payoutletbrowser.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/payoutletbrowser.py	(revision 15729)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/payoutletbrowser.py	(revision 15730)
@@ -39,5 +39,6 @@
 from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
 from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
-from kofacustom.nigeria.etranzact.tests import PAYOUTLET_QUERY_URL, TERMINAL_ID
+from kofacustom.nigeria.etranzact.tests import HOST, TERMINAL_ID, HTTPS
+from kofacustom.nigeria.etranzact.helpers import query_payoutlet
 
 grok.templatedir('browser_templates')
@@ -49,68 +50,4 @@
     except KeyError:
         return False
-
-# Requerying Etranzact Payoutlet payments
-
-def query_payoutlet(confirmation_number, payment, terminal_id, query_url):
-    postdict = {}
-    postdict['TERMINAL_ID'] = terminal_id
-    postdict['RESPONSE_URL'] = 'http://dummy'
-    postdict['CONFIRMATION_NO'] = confirmation_number
-    data = urllib.urlencode(postdict)
-    payment.conf_number = confirmation_number
-    try:
-        # Etranzact only accepts HTTP 1.1 requests. Therefore
-        # the urllib2 package is required here.
-        f = urllib2.urlopen(url=query_url, data=data)
-        success = f.read()
-        success = success.replace('\r\n','')
-        # Etranzact sends strange HTML tags which must be removed.
-        success = re.sub("<.*?>", "", success)
-        if 'CUSTOMER_ID' not in success:
-            msg = _('Invalid or unsuccessful callback: ${a}',
-                mapping = {'a': success})
-            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
-            payment.p_state = 'failed'
-            return False, msg, log
-        success = success.replace('%20',' ').split('&')
-        # We expect at least two parameters
-        if len(success) < 2:
-            msg = _('Invalid callback: ${a}', mapping = {'a': success})
-            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
-            payment.p_state = 'failed'
-            return False, msg, log
-        try:
-            success_dict = dict([tuple(i.split('=')) for i in success])
-        except ValueError:
-            msg = _('Invalid callback: ${a}', mapping = {'a': success})
-            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
-            payment.p_state = 'failed'
-            return False, msg, log
-    except IOError:
-        msg = _('Etranzact IOError')
-        log = 'Etranzact IOError'
-        return False, msg, log
-    payment.r_code = u'ET'
-    payment.r_company = u'etranzact'
-    payment.r_desc = u'%s' % success_dict.get('TRANS_DESCR')
-    payment.r_amount_approved = float(success_dict.get('TRANS_AMOUNT',0.0))
-    payment.r_card_num = None
-    payment.r_pay_reference = u'%s' % success_dict.get('RECEIPT_NO')
-    if payment.r_amount_approved != payment.amount_auth:
-        msg = _('Wrong amount')
-        log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
-        payment.p_state = 'failed'
-        return False, msg, log
-    customer_id = success_dict.get('CUSTOMER_ID')
-    if payment.p_id != customer_id:
-        msg = _('Wrong payment id')
-        log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
-        payment.p_state = 'failed'
-        return False, msg, log
-    log = 'valid callback for payment %s: %s' % (payment.p_id, success)
-    msg = _('Successful callback received')
-    payment.p_state = 'paid'
-    payment.payment_date = datetime.utcnow()
-    return True, msg, log
 
 class EtranzactEnterPinActionButtonApplicant(APABApplicant):
@@ -126,5 +63,5 @@
         if not module_activated(self.context.__parent__.__parent__.year):
             return ''
-        if self.context.p_state != 'unpaid':
+        if self.context.p_state in ('paid', 'waived'):
             return ''
         return self.view.url(self.view.context, self.target)
@@ -142,5 +79,5 @@
         if not module_activated(self.context.student.current_session):
             return ''
-        if self.context.p_state != 'unpaid':
+        if self.context.p_state in ('paid', 'waived'):
             return ''
         return self.view.url(self.view.context, self.target)
@@ -178,5 +115,6 @@
     grok.require('waeup.payStudent')
     terminal_id = TERMINAL_ID
-    query_url = PAYOUTLET_QUERY_URL
+    host = HOST
+    https = HTTPS
 
     def update(self, confirmation_number=None):
@@ -188,5 +126,6 @@
         student = self.context.student
         success, msg, log = query_payoutlet(
-            confirmation_number,self.context, self.terminal_id, self.query_url)
+            self.host, self.terminal_id, confirmation_number,
+            self.context, self.https)
         student.writeLogMessage(self, log)
         if not success:
@@ -210,5 +149,6 @@
     grok.require('waeup.payApplicant')
     terminal_id = TERMINAL_ID
-    query_url = PAYOUTLET_QUERY_URL
+    host = HOST
+    https = HTTPS
 
     def update(self, confirmation_number=None):
@@ -221,5 +161,6 @@
         applicant = self.context.__parent__
         success, msg, log = query_payoutlet(
-            confirmation_number,self.context, self.terminal_id, self.query_url)
+            self.host, self.terminal_id, confirmation_number,
+            self.context, self.https)
         applicant.writeLogMessage(self, log)
         if not success:
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/tests.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/tests.py	(revision 15729)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/tests.py	(revision 15730)
@@ -32,6 +32,5 @@
 from kofacustom.nigeria.students.payments import NigeriaStudentOnlinePayment
 from kofacustom.nigeria.testing import FunctionalLayer
-from kofacustom.nigeria.etranzact.helpers import (
-    query_history,)
+from kofacustom.nigeria.etranzact.helpers import query_history, query_payoutlet
 
 #from kofacustom.nigeria.etranzact.helpers import (query_etranzact)
@@ -43,10 +42,9 @@
 EXTERNAL_TESTS = True
 
-TERMINAL_ID = '0000000001'
+TERMINAL_ID = '5003021194'
 HOST = 'demo.etranzact.com'
 HTTPS = True
 SECRET_KEY = 'DEMO_KEY'
 LOGO_URL = 'https://iuokada.waeup.org/static_custom/iou_logo.png'
-PAYOUTLET_QUERY_URL = 'http://demo.etranzact.com/WebConnectPlus/query.jsp'
 
 # Valid transaction id in Etranzact system
@@ -149,4 +147,22 @@
         return
 
+    @external_test
+    def test_query_payoutlet(self):
+        # We've got some test numbers from Etranzact for testing
+        payment = NigeriaStudentOnlinePayment()
+        payment.p_id = 'p5723474039401'
+        success, msg, log = query_payoutlet(
+            HOST, '5003021194', '500854291572447457669', payment, True)
+        self.assertTrue(msg, 'Wrong amount')
+        payment.amount_auth = 200000.0
+        success, msg, log = query_payoutlet(
+            HOST, '5003021194', '500854291572447457669', payment, True)
+        self.assertTrue(success)
+        payment.p_id = 'xyz'
+        success, msg, log = query_payoutlet(
+            HOST, '5003021194', '500854291572447457669', payment, True)
+        self.assertTrue(msg, 'Wrong payment id')
+        return
+
 class EtranzactTestsApplicants(ApplicantsFullSetup):
     """Tests for the Etranzact payment gateway.
@@ -241,4 +257,14 @@
     def test_student_payoutlet_views(self):
         self.browser.getLink("Enter Etranzact PIN").click()
-        self.browser.getControl(name="confirmation_number").value = '1234'
+        self.browser.getControl(name="confirmation_number").value = '600854291572447457669'
         self.browser.getControl("Submit to Etranzact").click()
+        # This response is strange
+        self.assertTrue('-3:Wrong Setup' in self.browser.contents)
+        self.browser.getLink("Enter Etranzact PIN").click()
+        # This confirmation number exists
+        self.browser.getControl(name="confirmation_number").value = '500854291572447457669'
+        self.browser.getControl("Submit to Etranzact").click()
+        self.assertTrue('Wrong amount' in self.browser.contents)
+        # Some attributes have been set
+        self.assertEqual(self.payment.r_desc, 'Test Test Test-CLEARANCE -001-p5723474039401')
+        return
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/payments/interfaces.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/payments/interfaces.py	(revision 15729)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/payments/interfaces.py	(revision 15730)
@@ -26,4 +26,6 @@
 
     """
+
+    net_amount = Attribute('Total amount minus surcharges')
 
     ac = schema.TextLine(
@@ -107,2 +109,11 @@
         )
 
+    net_amt = schema.Float(
+        title = _(u'Net Amount'),
+        default = 0.0,
+        required = False,
+        readonly = True,
+        )
+
+INigeriaOnlinePayment['net_amt'].order = INigeriaOnlinePayment[
+    'amount_auth'].order
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py	(revision 15729)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py	(revision 15730)
@@ -114,5 +114,5 @@
     payment.r_amount_approved = jr['amount']
     payment.r_pay_reference = jr['RRR']
-    payment.r_company = u'remita'
+    #payment.r_company = u'remita'
     if payment.r_code not in ('00', '01'):
         msg = _('Unsuccessful response: ${a}', mapping = {'a': payment.r_desc})
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/students/payments.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/students/payments.py	(revision 15729)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/students/payments.py	(revision 15730)
@@ -64,6 +64,10 @@
             return None
 
+    @property
+    def net_amt(self):
+        return self.amount_auth - self.provider_amt - self.gateway_amt
+
 NigeriaStudentOnlinePayment = attrs_to_fields(NigeriaStudentOnlinePayment,
-    omit=['display_item'])
+    omit=['display_item', 'net_amt'])
 
 class NigeriaStudentOnlinePaymentFactory(StudentOnlinePaymentFactory):
