Ignore:
Timestamp:
31 Oct 2019, 20:14:47 (5 years ago)
Author:
Henrik Bettermann
Message:

Finalize Payoutlet integration.

Location:
main/kofacustom.nigeria/trunk/src/kofacustom/nigeria
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/applicants/payment.py

    r11639 r15730  
    4141        return
    4242
     43    @property
     44    def net_amt(self):
     45        return self.amount_auth - self.provider_amt - self.gateway_amt
     46
    4347NigeriaApplicantOnlinePayment = attrs_to_fields(
    44     NigeriaApplicantOnlinePayment, omit=['display_item'])
     48    NigeriaApplicantOnlinePayment, omit=['display_item', 'net_amt'])
    4549
    4650# Applicant online payments must be importable. So we might need a factory.
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/helpers.py

    r15702 r15730  
    2222from datetime import datetime
    2323from urllib import urlencode
     24from urllib2 import urlopen
     25from urlparse import parse_qs
    2426import httplib
    2527import hashlib
     
    193195    notify(grok.ObjectModifiedEvent(payment))
    194196    return True, msg, log
     197
     198# Requerying Etranzact Payoutlet payments
     199
     200# Expected response:
     201# RECEIPT_NO=500191030486&PAYMENT_CODE=500854291572447457669&MERCHANT_CODE=700602WDUB
     202# &TRANS_AMOUNT=200000.0&TRANS_DATE=2019/10/30
     203# 15:13:47&TRANS_DESCR=Test%20Test%20Test-CLEARANCE%20-001-p5723474039401
     204# &CUSTOMER_ID=p5723474039401&BANK_CODE=500&BRANCH_CODE=001
     205# &SERVICE_ID=p5723474039401&CUSTOMER_NAME=Test%20Test%20Test
     206# &CUSTOMER_ADDRESS=ASS-ENG&TELLER_ID=etzbankteller&USERNAME=%20
     207# &PASSWORD=%20&BANK_NAME=eTranzact%20Intl%20Plc
     208# &BRANCH_NAME=ETRANZACT&CHANNEL_NAME=Bank&PAYMENT_METHOD_NAME=Cash
     209# &PAYMENT_CURRENCY=566&TRANS_TYPE=101&TRANS_FEE=0.0
     210# &TYPE_NAME=CLEARANCE&LEAD_BANK_CODE=700&LEAD_BANK_NAME=eTranzact%20Intl%20Plc
     211# COL1=2018/2019&COL2=Acceptance
     212# Fee&COL3=ASS&COL4=ENG&COL5=BARTENL&COL6=400&COL7=ug_ft&COL8=N/A&COL9=11/12345
     213# &COL10=damms005@gmail.com&COL11=None&COL12=&COL13=
     214
     215def query_payoutlet(host, terminal_id, confirmation_number, payment, https):
     216    headers={"Content-type": "application/x-www-form-urlencoded",
     217             "Accept": "text/plain"}
     218    url = "/WebConnectPlus/query.jsp"
     219    if https:
     220        h = httplib.HTTPSConnection(host)
     221    else:
     222        h = httplib.HTTPConnection(host)
     223    args = {'TERMINAL_ID': terminal_id,
     224            'CONFIRMATION_NO': confirmation_number,
     225            }
     226    h.request('POST', url, urlencode(args), headers)
     227    response = h.getresponse()
     228    if response.status!=200:
     229        return False, 'Connection error (%s, %s)' % (response.status, response.reason), None
     230    raw = response.read()
     231    # Remove empty lines
     232    raw = raw.replace('\r\n','')
     233    success = parse_qs(raw)
     234    if not success.get('CUSTOMER_ID'):
     235        msg = _('Invalid or unsuccessful callback: ${a}',
     236            mapping = {'a': raw})
     237        log = 'invalid callback for payment %s: %s' % (payment.p_id, raw)
     238        payment.p_state = 'failed'
     239        return False, msg, log
     240    # We expect at least two parameters
     241    if len(success) < 2:
     242        msg = _('Invalid callback: ${a}', mapping = {'a': raw})
     243        log = 'invalid callback for payment %s: %s' % (payment.p_id, raw)
     244        payment.p_state = 'failed'
     245        return False, msg, log
     246    payment.r_code = u'ET'
     247    payment.r_desc = u'%s' % success.get('TRANS_DESCR')[0]
     248    payment.r_amount_approved = float(success.get('TRANS_AMOUNT')[0])
     249    payment.r_card_num = None
     250    payment.r_pay_reference = u'%s' % success.get('RECEIPT_NO')[0]
     251    if payment.r_amount_approved != payment.amount_auth:
     252        msg = _('Wrong amount')
     253        log = 'wrong callback for payment %s: %s' % (payment.p_id, raw)
     254        payment.p_state = 'failed'
     255        return False, msg, log
     256    customer_id = success.get('CUSTOMER_ID')[0]
     257    if payment.p_id != customer_id:
     258        msg = _('Wrong payment id')
     259        log = 'wrong callback for payment %s: %s' % (payment.p_id, raw)
     260        payment.p_state = 'failed'
     261        return False, msg, log
     262    log = 'valid callback for payment %s: %s' % (payment.p_id, raw)
     263    msg = _('Successful callback received')
     264    payment.p_state = 'paid'
     265    payment.payment_date = datetime.utcnow()
     266    return True, msg, log
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/payoutletbrowser.py

    r15702 r15730  
    3939from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
    4040from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
    41 from kofacustom.nigeria.etranzact.tests import PAYOUTLET_QUERY_URL, TERMINAL_ID
     41from kofacustom.nigeria.etranzact.tests import HOST, TERMINAL_ID, HTTPS
     42from kofacustom.nigeria.etranzact.helpers import query_payoutlet
    4243
    4344grok.templatedir('browser_templates')
     
    4950    except KeyError:
    5051        return False
    51 
    52 # Requerying Etranzact Payoutlet payments
    53 
    54 def query_payoutlet(confirmation_number, payment, terminal_id, query_url):
    55     postdict = {}
    56     postdict['TERMINAL_ID'] = terminal_id
    57     postdict['RESPONSE_URL'] = 'http://dummy'
    58     postdict['CONFIRMATION_NO'] = confirmation_number
    59     data = urllib.urlencode(postdict)
    60     payment.conf_number = confirmation_number
    61     try:
    62         # Etranzact only accepts HTTP 1.1 requests. Therefore
    63         # the urllib2 package is required here.
    64         f = urllib2.urlopen(url=query_url, data=data)
    65         success = f.read()
    66         success = success.replace('\r\n','')
    67         # Etranzact sends strange HTML tags which must be removed.
    68         success = re.sub("<.*?>", "", success)
    69         if 'CUSTOMER_ID' not in success:
    70             msg = _('Invalid or unsuccessful callback: ${a}',
    71                 mapping = {'a': success})
    72             log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
    73             payment.p_state = 'failed'
    74             return False, msg, log
    75         success = success.replace('%20',' ').split('&')
    76         # We expect at least two parameters
    77         if len(success) < 2:
    78             msg = _('Invalid callback: ${a}', mapping = {'a': success})
    79             log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
    80             payment.p_state = 'failed'
    81             return False, msg, log
    82         try:
    83             success_dict = dict([tuple(i.split('=')) for i in success])
    84         except ValueError:
    85             msg = _('Invalid callback: ${a}', mapping = {'a': success})
    86             log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
    87             payment.p_state = 'failed'
    88             return False, msg, log
    89     except IOError:
    90         msg = _('Etranzact IOError')
    91         log = 'Etranzact IOError'
    92         return False, msg, log
    93     payment.r_code = u'ET'
    94     payment.r_company = u'etranzact'
    95     payment.r_desc = u'%s' % success_dict.get('TRANS_DESCR')
    96     payment.r_amount_approved = float(success_dict.get('TRANS_AMOUNT',0.0))
    97     payment.r_card_num = None
    98     payment.r_pay_reference = u'%s' % success_dict.get('RECEIPT_NO')
    99     if payment.r_amount_approved != payment.amount_auth:
    100         msg = _('Wrong amount')
    101         log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
    102         payment.p_state = 'failed'
    103         return False, msg, log
    104     customer_id = success_dict.get('CUSTOMER_ID')
    105     if payment.p_id != customer_id:
    106         msg = _('Wrong payment id')
    107         log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
    108         payment.p_state = 'failed'
    109         return False, msg, log
    110     log = 'valid callback for payment %s: %s' % (payment.p_id, success)
    111     msg = _('Successful callback received')
    112     payment.p_state = 'paid'
    113     payment.payment_date = datetime.utcnow()
    114     return True, msg, log
    11552
    11653class EtranzactEnterPinActionButtonApplicant(APABApplicant):
     
    12663        if not module_activated(self.context.__parent__.__parent__.year):
    12764            return ''
    128         if self.context.p_state != 'unpaid':
     65        if self.context.p_state in ('paid', 'waived'):
    12966            return ''
    13067        return self.view.url(self.view.context, self.target)
     
    14279        if not module_activated(self.context.student.current_session):
    14380            return ''
    144         if self.context.p_state != 'unpaid':
     81        if self.context.p_state in ('paid', 'waived'):
    14582            return ''
    14683        return self.view.url(self.view.context, self.target)
     
    178115    grok.require('waeup.payStudent')
    179116    terminal_id = TERMINAL_ID
    180     query_url = PAYOUTLET_QUERY_URL
     117    host = HOST
     118    https = HTTPS
    181119
    182120    def update(self, confirmation_number=None):
     
    188126        student = self.context.student
    189127        success, msg, log = query_payoutlet(
    190             confirmation_number,self.context, self.terminal_id, self.query_url)
     128            self.host, self.terminal_id, confirmation_number,
     129            self.context, self.https)
    191130        student.writeLogMessage(self, log)
    192131        if not success:
     
    210149    grok.require('waeup.payApplicant')
    211150    terminal_id = TERMINAL_ID
    212     query_url = PAYOUTLET_QUERY_URL
     151    host = HOST
     152    https = HTTPS
    213153
    214154    def update(self, confirmation_number=None):
     
    221161        applicant = self.context.__parent__
    222162        success, msg, log = query_payoutlet(
    223             confirmation_number,self.context, self.terminal_id, self.query_url)
     163            self.host, self.terminal_id, confirmation_number,
     164            self.context, self.https)
    224165        applicant.writeLogMessage(self, log)
    225166        if not success:
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/tests.py

    r15702 r15730  
    3232from kofacustom.nigeria.students.payments import NigeriaStudentOnlinePayment
    3333from kofacustom.nigeria.testing import FunctionalLayer
    34 from kofacustom.nigeria.etranzact.helpers import (
    35     query_history,)
     34from kofacustom.nigeria.etranzact.helpers import query_history, query_payoutlet
    3635
    3736#from kofacustom.nigeria.etranzact.helpers import (query_etranzact)
     
    4342EXTERNAL_TESTS = True
    4443
    45 TERMINAL_ID = '0000000001'
     44TERMINAL_ID = '5003021194'
    4645HOST = 'demo.etranzact.com'
    4746HTTPS = True
    4847SECRET_KEY = 'DEMO_KEY'
    4948LOGO_URL = 'https://iuokada.waeup.org/static_custom/iou_logo.png'
    50 PAYOUTLET_QUERY_URL = 'http://demo.etranzact.com/WebConnectPlus/query.jsp'
    5149
    5250# Valid transaction id in Etranzact system
     
    149147        return
    150148
     149    @external_test
     150    def test_query_payoutlet(self):
     151        # We've got some test numbers from Etranzact for testing
     152        payment = NigeriaStudentOnlinePayment()
     153        payment.p_id = 'p5723474039401'
     154        success, msg, log = query_payoutlet(
     155            HOST, '5003021194', '500854291572447457669', payment, True)
     156        self.assertTrue(msg, 'Wrong amount')
     157        payment.amount_auth = 200000.0
     158        success, msg, log = query_payoutlet(
     159            HOST, '5003021194', '500854291572447457669', payment, True)
     160        self.assertTrue(success)
     161        payment.p_id = 'xyz'
     162        success, msg, log = query_payoutlet(
     163            HOST, '5003021194', '500854291572447457669', payment, True)
     164        self.assertTrue(msg, 'Wrong payment id')
     165        return
     166
    151167class EtranzactTestsApplicants(ApplicantsFullSetup):
    152168    """Tests for the Etranzact payment gateway.
     
    241257    def test_student_payoutlet_views(self):
    242258        self.browser.getLink("Enter Etranzact PIN").click()
    243         self.browser.getControl(name="confirmation_number").value = '1234'
     259        self.browser.getControl(name="confirmation_number").value = '600854291572447457669'
    244260        self.browser.getControl("Submit to Etranzact").click()
     261        # This response is strange
     262        self.assertTrue('-3:Wrong Setup' in self.browser.contents)
     263        self.browser.getLink("Enter Etranzact PIN").click()
     264        # This confirmation number exists
     265        self.browser.getControl(name="confirmation_number").value = '500854291572447457669'
     266        self.browser.getControl("Submit to Etranzact").click()
     267        self.assertTrue('Wrong amount' in self.browser.contents)
     268        # Some attributes have been set
     269        self.assertEqual(self.payment.r_desc, 'Test Test Test-CLEARANCE -001-p5723474039401')
     270        return
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/payments/interfaces.py

    r15702 r15730  
    2626
    2727    """
     28
     29    net_amount = Attribute('Total amount minus surcharges')
    2830
    2931    ac = schema.TextLine(
     
    107109        )
    108110
     111    net_amt = schema.Float(
     112        title = _(u'Net Amount'),
     113        default = 0.0,
     114        required = False,
     115        readonly = True,
     116        )
     117
     118INigeriaOnlinePayment['net_amt'].order = INigeriaOnlinePayment[
     119    'amount_auth'].order
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/helpers.py

    r14916 r15730  
    114114    payment.r_amount_approved = jr['amount']
    115115    payment.r_pay_reference = jr['RRR']
    116     payment.r_company = u'remita'
     116    #payment.r_company = u'remita'
    117117    if payment.r_code not in ('00', '01'):
    118118        msg = _('Unsuccessful response: ${a}', mapping = {'a': payment.r_desc})
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/students/payments.py

    r13623 r15730  
    6464            return None
    6565
     66    @property
     67    def net_amt(self):
     68        return self.amount_auth - self.provider_amt - self.gateway_amt
     69
    6670NigeriaStudentOnlinePayment = attrs_to_fields(NigeriaStudentOnlinePayment,
    67     omit=['display_item'])
     71    omit=['display_item', 'net_amt'])
    6872
    6973class NigeriaStudentOnlinePaymentFactory(StudentOnlinePaymentFactory):
Note: See TracChangeset for help on using the changeset viewer.