Index: main/waeup.aaue/trunk/src/waeup/aaue/etranzact/browser.py
===================================================================
--- main/waeup.aaue/trunk/src/waeup/aaue/etranzact/browser.py	(revision 15758)
+++ main/waeup.aaue/trunk/src/waeup/aaue/etranzact/browser.py	(revision 15759)
@@ -1,5 +1,5 @@
 ## $Id$
 ##
-## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## 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
@@ -16,465 +16,141 @@
 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##
-from datetime import datetime
-import httplib
-import urllib
-import urllib2
-import re
-from xml.dom.minidom import parseString
-import grok
-from zope.component import getUtility
-from zope.catalog.interfaces import ICatalog
-from waeup.kofa.interfaces import IUniversity, CLEARED
-from waeup.kofa.payments.interfaces import IPayer
-from waeup.kofa.webservices import PaymentDataWebservice
-from waeup.kofa.browser.layout import KofaPage, UtilityView
-from waeup.kofa.students.viewlets import ApprovePaymentActionButton as APABStudent
-from waeup.kofa.applicants.viewlets import ApprovePaymentActionButton as APABApplicant
-from waeup.aaue.interfaces import academic_sessions_vocab
-from kofacustom.nigeria.interswitch.browser import (
-    InterswitchActionButtonStudent,
-    InterswitchRequestWebserviceActionButtonStudent,
-    InterswitchActionButtonApplicant,
-    InterswitchRequestWebserviceActionButtonApplicant)
-from waeup.aaue.interfaces import MessageFactory as _
-from waeup.aaue.students.interfaces import ICustomStudentOnlinePayment
-from waeup.aaue.applicants.interfaces import ICustomApplicantOnlinePayment
 
-ERROR_PART1 = (
-        'PayeeName=N/A~'
-        + 'Faculty=N/A~'
-        + 'Department=N/A~'
-        + 'Level=N/A~'
-        + 'ProgrammeType=N/A~'
-        + 'StudyType=N/A~'
-        + 'Session=N/A~'
-        + 'PayeeID=N/A~'
-        + 'Amount=N/A~'
-        + 'FeeStatus=')
-ERROR_PART2 = (
-        '~Semester=N/A~'
-        + 'PaymentType=N/A~'
-        + 'MatricNumber=N/A~'
-        + 'Email=N/A~'
-        + 'PhoneNumber=N/A')
+from kofacustom.nigeria.etranzact.applicantsbrowser import (
+    EtranzactPageApplicant, EtranzactReceiveResponseApplicant,
+    EtranzactRequestPaymentStatusPageApplicant)
+from kofacustom.nigeria.etranzact.studentsbrowser import (
+    EtranzactPageStudent, EtranzactReceiveResponseStudent,
+    EtranzactRequestPaymentStatusPageStudent)
+from kofacustom.nigeria.etranzact.payoutletbrowser import (
+    EtranzactEnterPinPageStudent, EtranzactEnterPinPageApplicant,
+    EtranzactQueryHistoryPageStudent, EtranzactQueryHistoryPageApplicant)
+from kofacustom.nigeria.etranzact.payoutletwebservice  import NigeriaPaymentDataWebservice
 
-class CustomPaymentDataWebservice(PaymentDataWebservice):
+# Temporarily we can use the test portal like in kofacustom.nigeria
+
+from kofacustom.nigeria.etranzact.tests import (
+    HOST, HTTPS, SECRET_KEY, TERMINAL_ID, GATEWAY_AMT)
+
+#HOST = 'www.etranzact.net'
+#HTTPS = True
+#SECRET_KEY =
+#TERMINAL_ID = 0570000070
+#GATEWAY_AMT =
+LOGO_URL = 'https://iuokada.waeup.org/static_custom/iou_logo.png'
+
+class CustomEtranzactPageApplicant(EtranzactPageApplicant):
+
+    host = HOST
+    https = HTTPS
+    secret_key = SECRET_KEY
+    terminal_id = TERMINAL_ID
+    logo_url = LOGO_URL
+    gateway_amt = GATEWAY_AMT
+
+    def update(self):
+        # Already now it becomes an Etranzact payment. We set the net amount
+        # and add the gateway amount.
+        if not self.context.r_company:
+            self.context.net_amt = self.context.amount_auth
+            self.context.amount_auth += self.gateway_amt
+            self.context.gateway_amt = self.gateway_amt
+            self.context.r_company = u'etranzact'
+        self.amount = "%.1f" % self.context.amount_auth
+        error = self.init_update()
+        if error:
+            self.flash(error, type='danger')
+            self.redirect(self.url(self.context, '@@index'))
+            return
+        return
+
+class CustomEtranzactReceiveResponseApplicant(EtranzactReceiveResponseApplicant):
+
+    secret_key = SECRET_KEY
+    terminal_id = TERMINAL_ID
+
+class CustomEtranzactRequestPaymentStatusPageApplicant(
+    EtranzactRequestPaymentStatusPageApplicant):
+
+    host = HOST
+    https = HTTPS
+    secret_key = SECRET_KEY
+    terminal_id = TERMINAL_ID
+    logo_url = LOGO_URL
+
+class CustomEtranzactPageStudent(EtranzactPageStudent):
+
+    host = HOST
+    https = HTTPS
+    secret_key = SECRET_KEY
+    terminal_id = TERMINAL_ID
+    logo_url = LOGO_URL
+    gateway_amt = GATEWAY_AMT
+
+    def update(self):
+        # Already now it becomes an Etranzact payment. We set the net amount
+        # and add the gateway amount.
+        if not self.context.r_company:
+            self.context.net_amt = self.context.amount_auth
+            self.context.amount_auth += self.gateway_amt
+            self.context.gateway_amt = self.gateway_amt
+            self.context.r_company = u'etranzact'
+        self.amount = "%.1f" % self.context.amount_auth
+        error = self.init_update()
+        if error:
+            self.flash(error, type='danger')
+            self.redirect(self.url(self.context, '@@index'))
+            return
+        return
+
+class CustomEtranzactReceiveResponseStudent(EtranzactReceiveResponseStudent):
+
+    secret_key = SECRET_KEY
+    terminal_id = TERMINAL_ID
+
+class CustomEtranzactRequestPaymentStatusPageStudent(
+    EtranzactRequestPaymentStatusPageStudent):
+
+    host = HOST
+    https = HTTPS
+    secret_key = SECRET_KEY
+    terminal_id = TERMINAL_ID
+    logo_url = LOGO_URL
+
+# Payoutlet customizations
+
+class CustomEtranzactEnterPinPageStudent(EtranzactEnterPinPageStudent):
+    """Enter confirmation PIN and submit to `EtranzactQueryHistoryPageStudent`
+    """
+    gateway_amt = GATEWAY_AMT
+
+class CustomEtranzactEnterPinPageApplicant(EtranzactEnterPinPageApplicant):
+    """Enter confirmation PIN and submit to `EtranzactQueryHistoryPageApplicant`
+    """
+    gateway_amt = GATEWAY_AMT
+
+class CustomEtranzactQueryHistoryPageStudent(EtranzactQueryHistoryPageStudent):
+    """ Query history of Etranzact payments
+    """
+    terminal_id = TERMINAL_ID
+    host = HOST
+    https = HTTPS
+
+class CustomEtranzactQueryHistoryPageApplicant(EtranzactQueryHistoryPageApplicant):
+    """ Query history of Etranzact payments
+    """
+    terminal_id = TERMINAL_ID
+    host = HOST
+    https = HTTPS
+
+class CustomPaymentDataWebservice(NigeriaPaymentDataWebservice):
     """A simple webservice to publish payment and payer details on request from
     accepted IP addresses without authentication.
-
-    Etranzact is asking for the PAYEE_ID which is indeed misleading.
-    These are not the data of the payee but of the payer. And it's
-    not the id of the payer but of the payment.
     """
-    grok.name('feerequest')
-
     #ACCEPTED_IP = ('195.219.3.181', '195.219.3.184')
     ACCEPTED_IP = None
 
-    def update(self, PAYEE_ID=None, PAYMENT_TYPE=None):
+    CATEGORY_MAPPING = {
+        'SCHOOLFEE': ('schoolfee',),
+         }
 
-        # webservice disabled on 6/3/19
-        self.output = None
-        return
-
-        if PAYEE_ID == None:
-            self.output = ERROR_PART1 + 'Missing PAYEE_ID' + ERROR_PART2
-            return
-        real_ip = self.request.get('HTTP_X_FORWARDED_FOR', None)
-        # We can forego the logging once eTranzact payments run smoothly
-        # and the accepted IP addresses are used.
-        if real_ip:
-            self.context.logger.info('PaymentDataWebservice called: %s' % real_ip)
-        if real_ip  and self.ACCEPTED_IP:
-            if real_ip not in  self.ACCEPTED_IP:
-                self.output = ERROR_PART1 + 'Wrong IP address' + ERROR_PART2
-                return
-        category_mapping = {
-            'SCHOOL-FEE-NEW': ('schoolfee',),
-            'SCHOOL-FEE-RETURNING': ('schoolfee',),
-            'SCHOOL-FEE-PLUS-NEW': ('schoolfee_incl',),
-            'SCHOOL-FEE-PLUS-RETURNING': ('schoolfee_incl',),
-            'SCHOOL-FEE-PG-NEW': ('schoolfee',),
-            'SCHOOL-FEE-PG-RETURNING': ('schoolfee',),
-            'SCHOOL-FEE-FIRST-INSTALMENT-PLUS': ('schoolfee_1',),
-            'SCHOOL-FEE-SECOND-INSTALMENT': ('schoolfee_2',),
-            'SCHOOL-FEE-BALANCE': ('schoolfee','schoolfee_incl',
-                                   'schoolfee_1','schoolfee_2'),
-            'SCHOOL-FEE-PT-NEW': ('schoolfee',),
-            'SCHOOL-FEE-PT-RETURNING': ('schoolfee',),
-            'SCHOOL-FEE-PT-PLUS-NEW': ('schoolfee_incl',),
-            'SCHOOL-FEE-PT-PLUS-RETURNING': ('schoolfee_incl',),
-            'SCHOOL-FEE-PT-PG-NEW': ('schoolfee',),
-            'SCHOOL-FEE-PT-PG-RETURNING': ('schoolfee',),
-            'SCHOOL-FEE-PT-FIRST-INSTALMENT-PLUS': ('schoolfee_1',),
-            'SCHOOL-FEE-PT-SECOND-INSTALMENT': ('schoolfee_2',),
-            'SCHOOL-FEE-PT-BALANCE': ('schoolfee','schoolfee_incl',
-                                      'schoolfee_1','schoolfee_2'),
-            'SCHOOL-FEE-FP-NEW': ('schoolfee',),
-            'SCHOOL-FEE-IJMBE': ('schoolfee',),
-
-            'ACCEPTANCE-FEE': ('clearance',),
-            'ACCEPTANCE-FEE-PLUS': ('clearance_incl',),
-            'ACCEPTANCE-FEE-PG': ('clearance',),
-            'ACCEPTANCE-FEE-PT': ('clearance',),
-            'ACCEPTANCE-FEE-PT-PLUS': ('clearance_incl',),
-            'ACCEPTANCE-FEE-PT-PG': ('clearance',),
-            'ACCEPTANCE-FEE-FP': ('clearance',),
-            'ACCEPTANCE-FEE-IJMBE': ('clearance',),
-
-            'APPLICATION-FEE-UTME': ('application',),
-            'APPLICATION-FEE-PT': ('application',),
-            'APPLICATION-FEE-FP': ('application',),
-
-            'LATE-REGISTRATION': ('late_registration',),
-            'LATE-REGISTRATION-PT': ('late_registration',),
-
-            'AAU-STUDENT-WELFARE-ASSURANCE': ('welfare',),
-            'AAU-STUDENT-WELFARE-ASSURANCE-PT': ('welfare',),
-
-            'AAU-STUDENT-ID_CARD': ('id_card',),
-
-            'HOSTEL-ACCOMMODATION-FEE': ('hostel_maintenance',),
-            'HOSTEL-ACCOMMODATION-FEE-PT': ('hostel_maintenance',),
-
-            'AAU-LAPEL-FILE-FEE': ('lapel',),
-            'AAU-LAPEL-FILE-FEE-PT': ('lapel',),
-
-            'MATRICULATION-GOWN-FEE': ('matric_gown',),
-            'MATRICULATION-GOWN-FEE-PT': ('matric_gown',),
-
-            'CONCESSIONAL-FEE': ('concessional',),
-            'CONCESSIONAL-FEE-PT': ('concessional',),
-
-            'STUDENTS-UNION-DUES': ('union',),
-            'STUDENTS-UNION-DUES-PT': ('union',),
-
-            'RESTITUTION-FEE': ('restitution',),
-            }
-
-        if PAYMENT_TYPE not in category_mapping.keys():
-            self.output = ERROR_PART1 + 'Invalid PAYMENT_TYPE' + ERROR_PART2
-            return
-
-        # It seems eTranzact sends a POST request with an empty body but the URL
-        # contains a query string. So it's actually a GET request pretended
-        # to be a POST request. Although this does not comply with the
-        # RFC 2616 HTTP guidelines we may try to fetch the id from the QUERY_STRING
-        # value of the request.
-        #if PAYEE_ID is None:
-        #    try:
-        #        PAYEE_ID = self.request['QUERY_STRING'].split('=')[1]
-        #    except:
-        #        self.output = '-4'
-        #        return
-
-        cat = getUtility(ICatalog, name='payments_catalog')
-        results = list(cat.searchResults(p_id=(PAYEE_ID, PAYEE_ID)))
-        if len(results) != 1:
-            self.output = ERROR_PART1 + 'Invalid PAYEE_ID' + ERROR_PART2
-            return
-        student = getattr(results[0], 'student', None)
-        amount = results[0].amount_auth
-        payment_type = results[0].category
-        p_category = results[0].p_category
-        programme_type = results[0].p_item
-        if not programme_type:
-            programme_type = 'N/A'
-        academic_session = academic_sessions_vocab.getTerm(
-            results[0].p_session).title
-        status = results[0].p_state
-
-        if status == 'paid':
-            self.output = ERROR_PART1 + 'PAYEE_ID already used' + ERROR_PART2
-            return
-        if p_category not in category_mapping[PAYMENT_TYPE]:
-            self.output = ERROR_PART1 + 'Wrong PAYMENT_TYPE' + ERROR_PART2
-            return
-        if student and PAYMENT_TYPE.endswith('-RETURNING') \
-            and student.state == CLEARED:
-            self.output = ERROR_PART1 + 'Not a returning student' + ERROR_PART2
-            return
-        if student and PAYMENT_TYPE.endswith('-NEW') \
-            and student.state != CLEARED:
-            self.output = ERROR_PART1 + 'Not a new student' + ERROR_PART2
-            return
-        if student and '-PG' in PAYMENT_TYPE and not student.is_postgrad:
-            self.output = ERROR_PART1 + 'Not a postgrad student' + ERROR_PART2
-            return
-        if student and '-PG' not in PAYMENT_TYPE and student.is_postgrad \
-            and results[0].p_item != 'Balance':
-            self.output = ERROR_PART1 + 'Postgrad student' + ERROR_PART2
-            return
-        if student and '-PT' in PAYMENT_TYPE \
-            and not student.current_mode.endswith('_pt'):
-            self.output = ERROR_PART1 + 'Not a part-time student' + ERROR_PART2
-            return
-        if student and '-PT' not in PAYMENT_TYPE \
-            and student.current_mode.endswith('_pt'):
-            self.output = ERROR_PART1 + 'Part-time student' + ERROR_PART2
-            return
-        if student and '-FP' in PAYMENT_TYPE and student.current_mode != 'found':
-            self.output = ERROR_PART1 + 'Not a foundation programme student' + ERROR_PART2
-            return
-        if student and '-FP' not in PAYMENT_TYPE and student.current_mode == 'found':
-            self.output = ERROR_PART1 + 'Foundation programme student' + ERROR_PART2
-            return
-        if student and '-IJMBE' in PAYMENT_TYPE and student.current_mode != 'ijmbe':
-            self.output = ERROR_PART1 + 'Not IJMBE student' + ERROR_PART2
-            return
-        if student and '-IJMBE' not in PAYMENT_TYPE and student.current_mode == 'ijmbe':
-            self.output = ERROR_PART1 + 'IJMBE student student' + ERROR_PART2
-            return
-        if '-BALANCE' in PAYMENT_TYPE and results[0].p_item != 'Balance':
-            self.output = ERROR_PART1 + 'Not a balance payment' + ERROR_PART2
-            return
-        if not '-BALANCE' in PAYMENT_TYPE and results[0].p_item == 'Balance':
-            self.output = ERROR_PART1 + 'Balance payment' + ERROR_PART2
-            return
-
-        try:
-            owner = IPayer(results[0])
-            full_name = owner.display_fullname
-            matric_no = owner.id
-            faculty = owner.faculty
-            department = owner.department
-            study_type = owner.current_mode
-            email = owner.email
-            phone = owner.phone
-            level = owner.current_level
-        except (TypeError, AttributeError):
-            self.output = ERROR_PART1 +  'Unknown error' + ERROR_PART2
-            return
-        self.output = (
-            'PayeeName=%s~' +
-            'Faculty=%s~' +
-            'Department=%s~' +
-            'Level=%s~' +
-            'ProgrammeType=%s~' +
-            'StudyType=%s~' +
-            'Session=%s~' +
-            'PayeeID=%s~' +
-            'Amount=%s~' +
-            'FeeStatus=%s~' +
-            'Semester=N/A~' +
-            'PaymentType=%s~' +
-            'MatricNumber=%s~' +
-            'Email=%s~' +
-            'PhoneNumber=%s'
-
-            ) % (full_name, faculty,
-            department, level, programme_type, study_type,
-            academic_session, PAYEE_ID, amount, status, payment_type,
-            matric_no, email, phone)
-        return
-
-
-# Requerying eTranzact payments
-
-TERMINAL_ID = '0570000070'
-QUERY_URL =   'https://www.etranzact.net/WebConnectPlus/query.jsp'
-
-# Test environment
-#QUERY_URL =   'http://demo.etranzact.com:8080/WebConnect/queryPayoutletTransaction.jsp'
-#TERMINAL_ID = '5009892289'
-
-def query_etranzact(confirmation_number, payment):
-    
-    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):
-    grok.context(ICustomApplicantOnlinePayment)
-    grok.require('waeup.payApplicant')
-    grok.order(3)
-    icon = 'actionicon_call.png'
-    text = _('Query eTranzact History')
-    target = 'enterpin'
-
-class EtranzactEnterPinActionButtonStudent(APABStudent):
-    grok.context(ICustomStudentOnlinePayment)
-    grok.require('waeup.payStudent')
-    grok.order(3)
-    icon = 'actionicon_call.png'
-    text = _('Query eTranzact History')
-    target = 'enterpin'
-
-class EtranzactEnterPinPageStudent(KofaPage):
-    """
-    """
-    grok.context(ICustomStudentOnlinePayment)
-    grok.name('enterpin')
-    grok.template('enterpin')
-    grok.require('waeup.payStudent')
-
-    buttonname = _('Submit to eTranzact')
-    label = _('Requery eTranzact History')
-    action = 'query_history'
-    placeholder = _('Confirmation Number (PIN)')
-
-    def update(self):
-        super(EtranzactEnterPinPageStudent, self).update()
-        if not self.context.p_category.startswith('schoolfee'):
-            return
-        student = self.context.student
-        if student.state != CLEARED:
-            return
-        if student.entry_session < 2013:
-            return
-        for ticket in student['payments'].values():
-            if ticket.p_state == 'paid' and \
-                ticket.p_category.startswith('clearance'):
-                return
-        self.flash(_('Please pay acceptance fee first.'), type="danger")
-        self.redirect(self.url(self.context, '@@index'))
-        return
-
-class EtranzactEnterPinPageApplicant(EtranzactEnterPinPageStudent):
-    """
-    """
-    grok.require('waeup.payApplicant')
-    grok.context(ICustomApplicantOnlinePayment)
-
-class EtranzactQueryHistoryPageStudent(UtilityView, grok.View):
-    """ Query history of eTranzact payments
-    """
-    grok.context(ICustomStudentOnlinePayment)
-    grok.name('query_history')
-    grok.require('waeup.payStudent')
-
-    def update(self, confirmation_number=None):
-        if self.context.p_state == 'paid':
-            self.flash(_('This ticket has already been paid.'))
-            return
-        student = self.context.student
-        success, msg, log = query_etranzact(confirmation_number,self.context)
-        student.writeLogMessage(self, log)
-        if not success:
-            self.flash(msg)
-            return
-        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
-
-class EtranzactQueryHistoryPageApplicant(UtilityView, grok.View):
-    """ Query history of eTranzact payments
-    """
-    grok.context(ICustomApplicantOnlinePayment)
-    grok.name('query_history')
-    grok.require('waeup.payApplicant')
-
-    def update(self, confirmation_number=None):
-        ob_class = self.__implemented__.__name__
-        if self.context.p_state == 'paid':
-            self.flash(_('This ticket has already been paid.'))
-            return
-        applicant = self.context.__parent__
-        success, msg, log = query_etranzact(confirmation_number,self.context)
-        applicant.writeLogMessage(self, log)
-        if not success:
-            self.flash(msg)
-            return
-        flashtype, msg, log = self.context.doAfterApplicantPayment()
-        if log is not None:
-            applicant.writeLogMessage(self, log)
-        self.flash(msg, type=flashtype)
-        return
-
-    def render(self):
-        self.redirect(self.url(self.context, '@@index'))
-        return
-
-# Disable Interswitch viewlets. This could be avoided by defining the
-# action button viewlets of kofacustom.nigeria.interswitch.browser in the
-# context of INigeriaStudentOnlinePayment or INigeriaApplicantOnlinePayment
-# respectively. But then all interswitch.browser modules have to be extended.
-
-#class InterswitchActionButtonStudent(InterswitchActionButtonStudent):
-
-#    @property
-#    def target_url(self):
-#        return ''
-
-#class InterswitchRequestWebserviceActionButtonStudent(
-#    InterswitchRequestWebserviceActionButtonStudent):
-
-#    @property
-#    def target_url(self):
-#        return ''
-
-#class InterswitchActionButtonApplicant(InterswitchActionButtonApplicant):
-
-#    @property
-#    def target_url(self):
-#        return ''
-
-#class InterswitchRequestWebserviceActionButtonApplicant(
-#    InterswitchRequestWebserviceActionButtonApplicant):
-
-#    @property
-#    def target_url(self):
-#        return ''
Index: main/waeup.aaue/trunk/src/waeup/aaue/etranzact/tests.py
===================================================================
--- main/waeup.aaue/trunk/src/waeup/aaue/etranzact/tests.py	(revision 15758)
+++ 	(revision )
@@ -1,357 +1,0 @@
-## $Id$
-##
-## Copyright (C) 2011 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
-##
-from hurry.workflow.interfaces import IWorkflowState
-from zope.component import createObject, getUtility
-from waeup.kofa.students.tests.test_browser import StudentsFullSetup
-from waeup.kofa.applicants.tests.test_browser import (
-    ApplicantsFullSetup, session_1)
-from waeup.kofa.configuration import SessionConfiguration
-from waeup.aaue.testing import FunctionalLayer
-from waeup.aaue.etranzact.browser import ERROR_PART1, ERROR_PART2
-
-
-# Also run tests that send requests to external servers?
-#   If you enable this, please make sure the external services
-#   do exist really and are not bothered by being spammed by a test programme.
-EXTERNAL_TESTS = False
-
-def external_test(func):
-    if not EXTERNAL_TESTS:
-        myself = __file__
-        if myself.endswith('.pyc'):
-            myself = myself[:-2]
-        print "WARNING: external tests are skipped!"
-        print "WARNING: edit %s to enable them." % myself
-        return
-    return func
-
-class EtranzactTestsStudent(StudentsFullSetup):
-    """Tests for the eTranzact payment gateway.
-    """
-
-    layer = FunctionalLayer
-
-    CONFIRMATION_NO = '500856521315472785095'
-
-    def setUp(self):
-        super(EtranzactTestsStudent, self).setUp()
-        # Managers can add online payment tickets
-        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-        self.student['studycourse'].certificate.school_fee_1 = 1234.0
-        self.browser.open(self.payments_path)
-        IWorkflowState(self.student).setState('cleared')
-        self.student.nationality = u'NG'
-        self.browser.open(self.payments_path + '/addop')
-        self.browser.getControl(name="form.p_category").value = ['clearance_incl']
-        self.browser.getControl("Create ticket").click()
-        self.assertMatches('...ticket created...',
-                           self.browser.contents)
-        ctrl = self.browser.getControl(name='val_id')
-        value1 = ctrl.options[0]
-
-        self.browser.open(self.payments_path + '/addop')
-        self.browser.getControl(name="form.p_category").value = ['schoolfee_incl']
-        self.browser.getControl("Create ticket").click()
-        self.assertMatches('...ticket created...',
-                           self.browser.contents)
-        ctrl = self.browser.getControl(name='val_id')
-        value2 = ctrl.options[1]
-        self.p_id = value2
-        self.payment = self.student['payments'][value2]
-        self.browser.getLink(value2).click()
-        self.assertMatches('...Amount Authorized...',
-                           self.browser.contents)
-        self.payment_url = self.browser.url
-
-    def test_enterpin(self):
-        self.student['studycourse'].entry_session = 2013
-        self.browser.open(self.payment_url)
-        self.browser.getLink("Query eTranzact History").click()
-        self.assertTrue(
-            'Please pay acceptance fee firs' in self.browser.contents)
-        self.assertFalse(
-            'Confirmation Number (PIN)' in self.browser.contents)
-        self.student['payments'].values()[0].approve()
-        self.browser.getLink("Query eTranzact History").click()
-        self.assertFalse(
-            'Please pay acceptance fee firs' in self.browser.contents)
-        self.assertTrue(
-            'Confirmation Number (PIN)' in self.browser.contents)
-
-    def test_webservice(self):
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-PLUS-NEW'
-            % self.p_id)
-
-         # webservice disabled on 6/3/19
-        self.assertEqual(self.browser.contents, '')
-        return
-
-        self.assertEqual(self.browser.contents,
-            'PayeeName=TESTER, Anna~'
-            'Faculty=fac1~'
-            'Department=dep1~'
-            'Level=100~'
-            'ProgrammeType=CERT1~'
-            'StudyType=ug_ft~'
-            'Session=2004/2005~'
-            'PayeeID=%s~'
-            'Amount=1234.0~'
-            'FeeStatus=unpaid~'
-            'Semester=N/A~'
-            'PaymentType=School Fee Plus~'
-            'MatricNumber=E1000000~'
-            'Email=aa@aa.ng~'
-            'PhoneNumber=1234' % self.p_id)
-
-        self.browser.open('http://localhost/app/feerequest')
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Missing PAYEE_ID' + ERROR_PART2)
-
-        self.browser.open('http://localhost/app/feerequest?NONSENSE=nonsense')
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Missing PAYEE_ID' + ERROR_PART2)
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=nonsense&PAYMENT_TYPE=SCHOOL-FEE-NEW')
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Invalid PAYEE_ID' + ERROR_PART2)
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=NONSENSE'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Invalid PAYMENT_TYPE' + ERROR_PART2)
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Invalid PAYMENT_TYPE' + ERROR_PART2)
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=ACCEPTANCE-FEE'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Wrong PAYMENT_TYPE' + ERROR_PART2)
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=APPLICATION-FEE-UTME'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Wrong PAYMENT_TYPE' + ERROR_PART2)
-
-        # Change payment state
-        self.student['payments'][self.p_id].p_state = 'paid'
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-NEW'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'PAYEE_ID already used' + ERROR_PART2)
-
-        # Change workflow state and payment state
-        IWorkflowState(self.student).setState('returning')
-        self.student['payments'][self.p_id].p_state = 'unpaid'
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-NEW'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Wrong PAYMENT_TYPE' + ERROR_PART2)
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-BALANCE'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Not a balance payment' + ERROR_PART2)
-
-        # Change payment item
-        self.payment.p_item = u'Balance'
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-PLUS-RETURNING'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Balance payment' + ERROR_PART2)
-
-        # Change study mode
-        self.certificate.study_mode = 'special_pg_pt'
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-BALANCE'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Part-time student' + ERROR_PART2)
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-PT-BALANCE'
-            % self.p_id)
-        self.assertEqual(self.browser.contents,
-            'PayeeName=TESTER, Anna~'
-            'Faculty=fac1~'
-            'Department=dep1~'
-            'Level=100~'
-            'ProgrammeType=Balance~'
-            'StudyType=special_pg_pt~'
-            'Session=2004/2005~'
-            'PayeeID=%s~'
-            'Amount=1234.0~'
-            'FeeStatus=unpaid~'
-            'Semester=N/A~'
-            'PaymentType=School Fee Plus~'
-            'MatricNumber=E1000000~'
-            'Email=aa@aa.ng~'
-            'PhoneNumber=1234' % self.p_id)
-
-        # Change payment item
-        self.payment.p_item = u'CERT1'
-
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-PLUS-RETURNING'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Postgrad student' + ERROR_PART2)
-
-        # Cange payment category and study mode
-        self.payment.p_category = 'schoolfee'
-        self.certificate.study_mode = 'ug_ft'
-        
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-RETURNING'
-            % self.p_id)
-        self.assertEqual(self.browser.contents,
-            'PayeeName=TESTER, Anna~'
-            'Faculty=fac1~'
-            'Department=dep1~'
-            'Level=100~'
-            'ProgrammeType=CERT1~'
-            'StudyType=ug_ft~'
-            'Session=2004/2005~'
-            'PayeeID=%s~'
-            'Amount=1234.0~'
-            'FeeStatus=unpaid~'
-            'Semester=N/A~'
-            'PaymentType=School Fee~'
-            'MatricNumber=E1000000~'
-            'Email=aa@aa.ng~'
-            'PhoneNumber=1234' % self.p_id)
-
-        IWorkflowState(self.student).setState('cleared')
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-FP-NEW'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Not a foundation programme student' + ERROR_PART2)
-        self.certificate.study_mode = 'found'
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOL-FEE-NEW'
-            % self.p_id)
-        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Foundation programme student' + ERROR_PART2)
-
-    @external_test
-    def test_etranzact_query_history(self):
-
-        self.browser.open(self.payment_url + '/query_history?confirmation_number=%s'
-            % self.CONFIRMATION_NO)
-        self.assertMatches('...Invalid or unsuccessful callback:...',
-                          self.browser.contents)
-        #self.assertMatches('...Wrong amount...',
-        #                  self.browser.contents)
-        #self.student['payments'][value].amount_auth = self.student[
-        #    'payments'][value].r_amount_approved
-        #self.browser.open(self.payment_url + '/query_history?confirmation_number=%s'
-        #    % self.CONFIRMATION_NO)
-        #self.assertMatches('...Wrong transaction id...',
-        #                  self.browser.contents)
-
-class EtranzactTestsApplicants(ApplicantsFullSetup):
-    """Tests for the Interswitch payment gateway.
-    """
-
-    layer = FunctionalLayer
-
-    CONFIRMATION_NO = '500856521315472785095'
-
-    def setUp(self):
-        super(EtranzactTestsApplicants, self).setUp()
-        certificate = createObject('waeup.Certificate')
-        certificate.code = 'CERT2'
-        certificate.title = 'New Certificate'
-        certificate.application_category = 'basic'
-        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
-            certificate)
-        self.applicantscontainer.application_fee = 200.0
-        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-        self.browser.open(self.manage_path)
-        #IWorkflowState(self.student).setState('started')
-        super(EtranzactTestsApplicants, self).fill_correct_values()
-        self.browser.getControl(name="transition").value = ['start']
-        self.browser.getControl(name="form.nationality").value = ['NG']
-        self.browser.getControl(name="form.course2").value = ['CERT2']
-        #self.browser.getControl(name="form.programme_type").value = ['direct']
-        self.browser.getControl("Save").click()
-        self.browser.getControl("Add online").click()
-        self.assertTrue(
-            'Session configuration object is not available'
-            in self.browser.contents)
-        configuration = SessionConfiguration()
-        configuration.academic_session = session_1
-        self.applicantscontainer.application_fee = 1000.0
-        self.app['configuration'].addSessionConfiguration(configuration)
-        self.browser.open(self.manage_path)
-        self.browser.getControl("Add online").click()
-        self.assertMatches('...ticket created...',
-                           self.browser.contents)
-        self.assertMatches('...Amount Authorized...',
-                           self.browser.contents)
-        self.assertMatches(
-            '...<span>1000.0</span>...',
-            self.browser.contents)
-        self.payment_url = self.browser.url
-        self.browser.open(self.manage_path)
-        ctrl = self.browser.getControl(name='val_id')
-        value = ctrl.options[0]
-        self.p_id = value
-
-    def test_webservice(self):
-        self.browser.open(
-            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=APPLICATION-FEE-UTME'
-            % self.p_id)
-
-         # webservice disabled on 6/3/19
-        self.assertEqual(self.browser.contents, '')
-        return
-
-        self.assertEqual(self.browser.contents,
-            'PayeeName=TESTER, John Anthony~'
-            'Faculty=N/A~'
-            'Department=N/A~'
-            'Level=N/A~'
-            'ProgrammeType=This is the app%s container~'
-            'StudyType=N/A~'
-            'Session=%s/%s~'
-            'PayeeID=%s~'
-            'Amount=1000.0~'
-            'FeeStatus=unpaid~'
-            'Semester=N/A~'
-            'PaymentType=Application Fee~'
-            'MatricNumber=%s~'
-            'Email=xx@yy.zz~'
-            'PhoneNumber=None' % (
-                session_1, session_1, session_1+1,
-                self.p_id,self.applicant.applicant_id))
-
-    @external_test
-    def test_etranzact_query_history(self):
-
-        self.browser.open(self.payment_url + '/query_history?confirmation_number=%s'
-            % self.CONFIRMATION_NO)
-        self.assertMatches('...Invalid or unsuccessful callback:...',
-                          self.browser.contents)
-        #self.assertMatches('...Wrong amount...',
-        #                  self.browser.contents)
-        #self.applicant[value].amount_auth = self.applicant[
-        #    value].r_amount_approved
-        #self.browser.open(self.payment_url + '/query_history?confirmation_number=%s'
-        #    % self.CONFIRMATION_NO)
-        #self.assertMatches('...Wrong transaction id...',
-        #                  self.browser.contents)
