Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/browser.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/browser.py	(revision 14743)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/browser.py	(revision 14743)
@@ -0,0 +1,204 @@
+## $Id$
+##
+## Copyright (C) 2017 Uli Fouquet & Henrik Bettermann
+## This program 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.
+##
+## This program 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 this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+import grok
+import hashlib
+from datetime import datetime, timedelta
+from zope.component import getUtility
+from zope.security import checkPermission
+from waeup.kofa.interfaces import IKofaUtils
+from waeup.kofa.utils.helpers import to_timezone
+from waeup.kofa.browser.layout import UtilityView, KofaPage
+from waeup.kofa.browser.viewlets import ManageActionButton
+from waeup.kofa.students.interfaces import IStudentsUtils
+from waeup.kofa.students.browser import OnlinePaymentDisplayFormPage as OPDPStudent
+from waeup.kofa.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant
+from kofacustom.nigeria.remita.helpers import (
+    get_JSON_POST_response, query_remita, write_payments_log)
+from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
+from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
+from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
+from kofacustom.nigeria.interfaces import MessageFactory as _
+
+def module_activated(session):
+    try:
+        return getattr(grok.getSite()['configuration'][str(session)],
+            'remita_enabled', None)
+    except KeyError:
+        return False
+
+# Buttons
+
+class RemitaActionButtonStudent(ManageActionButton):
+    grok.order(1)
+    grok.context(INigeriaOnlinePayment)
+    grok.view(OPDPStudent)
+    grok.require('waeup.payStudent')
+    icon = 'actionicon_pay.png'
+    text = _('Pay via Remita')
+    target = 'goto_remita'
+
+    @property
+    def target_url(self):
+        if not module_activated(self.context.student.current_session):
+            return ''
+        if self.context.p_state != 'unpaid':
+            return ''
+        return self.view.url(self.view.context, self.target)
+
+# Webservice request views
+
+class RemitaPaymentRequestWebservicePageStudent(UtilityView, grok.View):
+    """ Request webservice view for the Remita gateway.
+    """
+    grok.context(INigeriaStudentOnlinePayment)
+    grok.name('request_payment_status')
+    grok.require('waeup.payStudent')
+
+    # Here we use Remita test portal data
+    merchantId = '2547916'
+    host = 'www.remitademo.net'
+    https = False
+    api_key = '1946'
+
+    def update(self):
+        if not module_activated(self.context.student.current_session):
+            return
+        if self.context.p_state in ('paid', 'waived'):
+            self.flash(_('This ticket has already been paid.'), type='danger')
+            return
+        student = self.context.student
+        RRR = self.context.r_pay_reference
+        if not RRR:
+            self.flash(_('Remita Retrieval Reference not found.'), type='danger')
+            return
+
+        # Remita sends a POST request which may contain more information
+        # if a payment was not successful.
+        resp = self.request.form
+        if resp and resp.get('statuscode') not in ('025', '00', '01'):
+            self.flash('Message from Remita: %s.'
+                % resp.get('status'), type='danger')
+
+        success, msg, log = query_remita(
+            self.context,
+            self.merchantId,
+            self.api_key,
+            RRR,
+            self.host,
+            self.https,
+            False)
+
+        student.writeLogMessage(self, log)
+        if not success:
+            self.flash(msg, type='danger')
+            return
+        write_payments_log(student.student_id, self.context)
+        flashtype, msg, log = self.context.doAfterStudentPayment()
+        if log is not None:
+            student.writeLogMessage(self, log)
+        self.flash(msg, type=flashtype)
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
+
+# Forwarding pages
+
+class RemitaPageStudent(KofaPage):
+    """ View which sends a POST request to the Remita payment gateway.
+    """
+    grok.context(INigeriaOnlinePayment)
+    grok.name('goto_remita')
+    grok.template('student_goto_remita')
+    grok.require('waeup.payStudent')
+    label = _('Pay via Remita')
+    submit_button = _('Pay now')
+    https = False
+
+    # Here we use Remita test portal data
+    merchantId = '2547916'
+    serviceTypeId = '4430731'
+    api_key = '1946'
+    orderId = '3456346346'
+    host = 'www.remitademo.net'
+    init_url = '/remita/ecomm/split/init.reg'
+    amount='1000'
+    lineitems = (
+                  {"lineItemsId":"itemid1","beneficiaryName":"Klaus Mueller",
+                  "beneficiaryAccount":"6020067886","bankCode":"011",
+                  "beneficiaryAmount":"500","deductFeeFrom":"1"},
+                  {"lineItemsId":"itemid2","beneficiaryName":"Werner Rumm",
+                  "beneficiaryAccount":"0360883515","bankCode":"050",
+                  "beneficiaryAmount":"500","deductFeeFrom":"0"}
+                )
+
+    action = 'http://www.remitademo.net/remita/ecomm/finalize.reg'
+
+    def init_update(self):
+        if self.context.p_state == 'paid':
+            return _("Payment ticket can't be re-sent to Remita.")
+        now = datetime.utcnow()
+        if self.context.creation_date.tzinfo is not None:
+            # That's bad. Please store timezone-naive datetimes only!
+            now = self.context.creation_date.tzinfo.localize(now)
+        time_delta = now - self.context.creation_date
+        if time_delta.days > 7:
+            return _("This payment ticket is too old. Please create a new ticket.")
+        student = self.context.student
+        certificate = getattr(student['studycourse'],'certificate',None)
+        if certificate is None:
+            return _("Study course data are incomplete.")
+        kofa_utils = getUtility(IKofaUtils)
+        student_utils = getUtility(IStudentsUtils)
+        if student_utils.samePaymentMade(student, self.context.p_category,
+            self.context.p_item, self.context.p_session):
+            return _("This type of payment has already been made.")
+        self.responseurl = self.url(self.context, 'request_payment_status')
+        self.student = student
+        resp = get_JSON_POST_response(
+            merchantId=self.merchantId,
+            serviceTypeId=self.serviceTypeId,
+            api_key=self.api_key,
+            orderId=self.orderId,
+            amount=self.amount,
+            responseurl=self.responseurl,
+            host=self.host,
+            url=self.init_url,
+            https=self.https,
+            fullname=self.student.display_fullname,
+            email=self.student.email,
+            lineitems=self.lineitems)
+        if resp.get('error'):
+            return resp.get('error')
+        if resp.get('statuscode') not in ('021', '025', '055'):
+            return resp.get('status') + '. Please check your email address.'
+        self.rrr = self.context.r_pay_reference = resp['RRR'].rstrip()
+        hashargs = 	self.merchantId + self.rrr + self.api_key
+        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
+        return
+
+    def update(self):
+        if not module_activated(self.context.student.current_session):
+            return
+        error = self.init_update()
+        if error:
+            self.flash(error, type='danger')
+            self.redirect(self.url(self.context, '@@index'))
+            return
+        return
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/browser_templates/student_goto_remita.pt
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/browser_templates/student_goto_remita.pt	(revision 14743)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/browser_templates/student_goto_remita.pt	(revision 14743)
@@ -0,0 +1,63 @@
+<form i18n:domain="kofacustom.nigeria"
+  tal:attributes="action view/action" method="POST">
+
+  <p i18n:translate="">
+    Your payment details were sent to Remita and a retrieval reference
+    number (RRR) has been generated. Please click button below to make
+    your RRR payment.
+  </p>
+
+  <table class="form-table" i18n:domain="waeup.kofa">
+    <tbody>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Total Amount Authorized:</td>
+        <td>
+          <span tal:replace="view/context/amount_auth">AMOUNT</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Order Id:</td>
+        <td>
+          <span tal:replace="view/context/p_id">ORDERID</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Remita Retrieval Reference:</td>
+        <td>
+          <span tal:replace="view/rrr">RRR</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Customer Name:</td>
+        <td>
+          <span tal:replace="view/student/display_fullname">CUSTNAME</span>
+        </td>
+      </tr>
+      <tr>
+        <td i18n:translate="" class="fieldname">
+          Email Address:</td>
+        <td>
+          <span tal:replace="view/student/email">EMAIL</span>
+        </td>
+      </tr>
+    </tbody>
+  </table>
+
+  <input name="merchantId" tal:attributes="value view/merchantId" type="hidden">
+  <input name="hash" tal:attributes="value view/hashvalue" type="hidden">
+  <input name="rrr" tal:attributes="value view/rrr" type="hidden">
+  <input name="responseurl" tal:attributes="value view/responseurl" type="hidden">
+
+  <br />
+
+  <input type="submit" class="btn btn-primary" tal:attributes="value view/submit_button"/>
+
+  <br /><br />
+
+  <img src="/static/img/remita-payment-logo-horizonal.png" />
+
+</form>
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py	(revision 14742)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py	(revision 14743)
@@ -61,5 +61,4 @@
     return parsed_json
 
-
 def get_payment_status_via_rrr(merchantId, api_key, RRR, host, https):
     RRR = RRR.rstrip()
@@ -84,5 +83,4 @@
         return {'error': 'No JSON response'}
     return parsed_json
-
 
 def query_remita(payment, merchantId, api_key, RRR, host, https, verify):
@@ -111,5 +109,5 @@
     payment.r_pay_reference = jr['RRR']
     payment.r_company = u'remita'
-    if payment.r_code != '00':
+    if payment.r_code not in ('00', '01'):
         msg = _('Unsuccessful callback: ${a}', mapping = {'a': payment.r_desc})
         log = 'unsuccessful callback for %s payment %s: %s' % (
@@ -141,5 +139,4 @@
     return True, msg, log
 
-
 def write_payments_log(id, payment):
     payment.logger.info(
Index: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/tests.py
===================================================================
--- main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/tests.py	(revision 14742)
+++ main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/tests.py	(revision 14743)
@@ -46,5 +46,4 @@
     return func
 
-
 class HelperTests(unittest.TestCase):
 
@@ -84,5 +83,4 @@
             u'statuscode': u'055'}
 
-
     @external_test
     def test_payment_status_via_rrr(self):
@@ -106,5 +104,4 @@
             u'RRR': u'320007640976'}
 
-
 class RemitaTestsStudents(StudentsFullSetup):
     """Tests for the Remita payment gateway.
@@ -123,4 +120,5 @@
     def setUp(self):
         super(RemitaTestsStudents, self).setUp()
+        self.app['configuration']['2004'].remita_enabled = True
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
         self.browser.open(self.payments_path)
@@ -141,5 +139,4 @@
         self.payment = self.student['payments'][self.value]
 
-
     @external_test
     def test_query_remita(self):
@@ -159,2 +156,13 @@
             u'unsuccessful callback for schoolfee payment %s: Transaction Pending'
             % self.payment.p_id)
+
+    @external_test
+    def test_remita_form(self):
+        # Manager can access InterswitchForm
+        self.browser.getLink("Pay via Remita").click()
+        # The RRR has been retrieved
+        self.assertTrue('<input name="rrr" type="hidden" value="280007640804">'
+            in self.browser.contents)
+        self.assertEqual(self.payment.r_pay_reference, '280007640804')
+        # Means of testing end here.
+        return
