Ignore:
Timestamp:
17 Sep 2019, 18:31:10 (5 years ago)
Author:
Henrik Bettermann
Message:

Backup work. Waiting for answers from eTranzact.

Location:
main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/applicantsbrowser.py

    r15586 r15589  
    2626from waeup.kofa.browser.viewlets import ManageActionButton
    2727from waeup.kofa.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant
    28 from kofacustom.nigeria.etranzact.helpers import (write_payments_log)
     28from kofacustom.nigeria.etranzact.helpers import (
     29    write_payments_log, process_response, query_history)
     30from kofacustom.nigeria.applicants.browser import NigeriaOnlinePaymentDisplayFormPage
    2931from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
    3032from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
     
    4244    except KeyError:
    4345        return False
    44 
    45 # Buttons
    4646
    4747class EtranzactActionButtonApplicant(ManageActionButton):
     
    6161            return ''
    6262        return self.view.url(self.view.context, self.target)
    63 
    64 # Forwarding pages
    6563
    6664class EtranzactPageApplicant(KofaPage):
     
    9694        if time_delta.days > 7:
    9795            return _("This payment ticket is too old. Please create a new ticket.")
    98         self.responseurl = self.url(self.context, 'query_etranzact')
     96        self.responseurl = self.url(self.context, 'receive_etranzact')
    9997        # Already now it becomes a eTranzact payment
    10098        self.context.r_company = u'etranzact'
     
    116114            return
    117115        return
     116
     117class EtranzactReceiveResponseApplicant(NigeriaOnlinePaymentDisplayFormPage):
     118    """ View that receives the response from eTrantact payment gateway.
     119    """
     120    #grok.context(INigeriaApplicantOnlinePayment)
     121    grok.name('receive_etranzact')
     122    #grok.require('waeup.payApplicant')
     123    #label = _('Response from eTranzact')
     124
     125    secret_key = SECRET_KEY
     126    terminal_id = TERMINAL_ID
     127
     128    def update(self):
     129        super(EtranzactReceiveResponseApplicant, self).update()
     130        if not module_activated(self.context.__parent__.__parent__.year):
     131            return
     132        applicant = self.context.__parent__
     133        form = self.request.form
     134        verify = False
     135        if self.context.p_state == 'paid':
     136            verify = True
     137        success, msg, log = process_response(self.context, form, self, verify)
     138        applicant.writeLogMessage(self, log)
     139        if not success:
     140            self.flash(msg, type='danger')
     141            return
     142        write_payments_log(applicant.applicant_id, self.context)
     143        flashtype, msg, log = self.context.doAfterApplicantPayment()
     144        if log is not None:
     145            applicant.writeLogMessage(self, log)
     146        self.flash(msg, type=flashtype)
     147        return
     148
     149class EtranzactRequeryHistoryApplicant(KofaPage):
     150    """ Request POST redirect from eTranzact
     151    """
     152
     153    grok.context(INigeriaApplicantOnlinePayment)
     154    grok.name('requery_history')
     155    grok.require('waeup.payApplicant')
     156    grok.template('requery_etranzact')
     157    label = _('Requery eTranzact history')
     158    submit_button = _('Requery now')
     159
     160    host = HOST
     161    https = HTTPS
     162    secret_key = SECRET_KEY
     163    terminal_id = TERMINAL_ID
     164    logo_url = LOGO_URL
     165
     166    @property
     167    def action(self):
     168        if self.https:
     169            return 'https://' + self.host + '/webconnect/v3/query.jsp'
     170        return 'http://' + self.host + '/webconnect/v3/query.jsp'
     171
     172    def update(self):
     173        if not module_activated(self.context.__parent__.__parent__.year):
     174            return
     175        self.responseurl = self.url(self.context, 'receive_etranzact')
     176        self.transaction_id = self.context.p_id
     177        return
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/helpers.py

    r15586 r15589  
    3737        payment.thirdparty_amt))
    3838
    39 def get_caller_response(host, https, terminal_id, transaction_id, responseurl,
    40                         amount_auth, email, phone, display_fullname, hashvalue,
    41                         logo_url):
    42     headers={"Content-type": "application/x-www-form-urlencoded",
    43              "Accept": "text/plain"}
    44     url = "/webconnect/v3/caller.jsp"
    45     if https:
    46         h = httplib.HTTPSConnection(host)
    47     else:
    48         h = httplib.HTTPConnection(host)
    49     args = {'TERMINAL_ID': terminal_id,
    50             'TRANSACTION_ID': transaction_id,
    51             'RESPONSE_URL': responseurl,
    52             'AMOUNT': amount_auth,
    53             'EMAIL': email,
    54             'PHONENO': phone,
    55             'FULL_NAME': display_fullname,
    56             'CURRENCY_CODE': 'NGN',
    57             'CHECKSUM': hashvalue,
    58             'LOGO_URL': logo_url,
    59             }
    60     h.request('POST', url, urlencode(args), headers)
    61     return
    62     response = h.getresponse()
    63     if response.status!=200:
    64         return 'Connection error (%s, %s)' % (response.status, response.reason)
    65     resp = response.read()
    66     return resp
    67     #resp = resp.replace('\r\n','')
    68     ## eTranzact sends strange HTML tags which must be removed.
    69     #resp = re.sub("<.*?>", "", resp)
    70     #return resp
    71 
    72 def get_query_response(host, terminal_id, transaction_id, https):
     39def query_history(host, terminal_id, transaction_id, https, responseurl):
    7340    headers={"Content-type": "application/x-www-form-urlencoded",
    7441             "Accept": "text/plain"}
     
    8047    args = {'TERMINAL_ID': terminal_id,
    8148            'TRANSACTION_ID': transaction_id,
    82             'RESPONSE_URL': 'https://www.waeup.org'}
     49            }
     50    #args['RESPONSE_URL'] = responseurl
    8351    h.request('POST', url, urlencode(args), headers)
    8452    response = h.getresponse()
     
    9058    resp = re.sub("<.*?>", "", resp)
    9159    return resp
     60
     61 # A sample caller response sent to the RESPONSE_URL
     62
     63 # http://salsa:8080/app/applicants/cbt2015/449072/p5679522929425/receive_etranzact?
     64 # AMOUNT=3333.0&
     65 # DESCRIPTION=&
     66 # CHECKSUM=8aab3904652f8ba69ebed42d3bae80a2&
     67 # EMAIL=aa%40aa.de&
     68 # SUCCESS=C&
     69 # MESSAGE=Cancel&
     70 # LOGO_URL=https%3A%2F%2Fiuokada.waeup.org%2Fstatic_custom%2Fiou_logo.png&
     71 # RESPONSE_URL=http%3A%2F%2Fsalsa%3A8080%2Fapp%2Fapplicants%2Fcbt2015%2F449072%2Fp5679522929425%2Freceive_etranzact&
     72 # CURRENCY_CODE=NGN&
     73 # TERMINAL_ID=0000000001&
     74 # TRANSACTION_ID=p5679522929425&
     75 # MERCHANT_CODE=0339990001&
     76 # RESPONSE_CODE=C&
     77 # FINAL_CHECKSUM=E524590DBFAB719EEE428C778FFF1650&
     78 # STATUS_REASON=Cancel&
     79 # TRANS_NUM=01ESA20190913062149AHGUHQ&
     80 # CARD_NO=null&
     81 # CARD_TYPE=null
     82
     83  # A sample query response sent to the RESPONSE_URL
     84
     85 # http://salsa:8080/app/applicants/cbt2015/449072/p5686487280654/receive_etranzact?
     86 # LOGO_URL=https%3A%2F%2Fiuokada.waeup.org%2Fstatic_custom%2Fiou_logo.png&
     87 # RESPONSE_URL=http%3A%2F%2Fsalsa%3A8080%2Fapp%2Fapplicants%2Fcbt2015%2F449072%2Fp5686487280654%2Freceive_etranzact&
     88 # CURRENCY_CODE=NGN&
     89 # TERMINAL_ID=0000000001&
     90 # TRANSACTION_ID=p5686487280654&
     91 # AMOUNT=3333.0&
     92 # DESCRIPTION=&
     93 # CHECKSUM=3886118fcd91a376cc95c48c94dc499a&
     94 # MERCHANT_CODE=0339990001&
     95 # EMAIL=aa%40aa.de&
     96 # SUCCESS=0&
     97 # FINAL_CHECKSUM=EE105B703F84B1D67D0A4234622C03E8&
     98 # STATUS_REASON=Approved&
     99 # TRANS_NUM=01ESA20190916164636L2UTU7&
     100 # CARD_NO=506066XXXXXXXXX6666&
     101 # CARD_TYPE=Verve
     102
     103def process_response(payment, form, view, verify):
     104    success = form.get('RESPONSE_CODE', None)
     105    if not success:
     106        msg = _('No valid response from eTranzact.')
     107        log = 'No valid response from eTranzact for payment %s' % payment.p_id
     108        payment.p_state = 'failed'
     109        notify(grok.ObjectModifiedEvent(payment))
     110        return False, msg, log
     111    # Compute final checksum
     112    transaction_id = payment.p_id
     113    amount = "%.1f" % payment.amount_auth
     114    responseurl = view.url(payment, 'receive_etranzact')
     115    hashargs =  success + amount + view.terminal_id + transaction_id \
     116        + responseurl + view.secret_key
     117    final_checksum = hashlib.md5(hashargs).hexdigest().upper()
     118    if form.get('FINAL_CHECKSUM', None) != final_checksum:
     119        msg = _('Wrong checksum.')
     120        log = 'wrong checksum for %s payment %s: %s' % (
     121            payment.p_category, payment.p_id, str(form))
     122        return False, msg, log
     123    payment.r_code = form.get('RESPONSE_CODE', None)
     124    payment.r_desc = form.get('STATUS_REASON', None) # MESSAGE also available
     125    payment.r_amount_approved = float(form.get('AMOUNT', None))
     126    payment.r_pay_reference = form.get('TRANS_NUM', None)
     127    payment.r_card_num = "%s %s" % (form.get('CARD_TYPE', None),
     128                                    form.get('CARD_NO', None))
     129    payment.r_company = u'etranzact'
     130    if payment.r_code != '0':
     131        msg = _('Unsuccessful response: ${a}', mapping = {'a': payment.r_desc})
     132        log = 'unsuccessful response for %s payment %s: %s' % (
     133            payment.p_category, payment.p_id, payment.r_desc)
     134        payment.p_state = 'failed'
     135        notify(grok.ObjectModifiedEvent(payment))
     136        return False, msg, log
     137    if round(payment.r_amount_approved/10.0, 0) != round(
     138        payment.amount_auth/10.0, 0):
     139        msg = _('Response amount does not match.')
     140        log = 'wrong response for %s payment %s: %s' % (
     141            payment.p_category, payment.p_id, str(form))
     142        payment.p_state = 'failed'
     143        notify(grok.ObjectModifiedEvent(payment))
     144        return False, msg, log
     145    transaction_id = form.get('TRANSACTION_ID', None)
     146    if transaction_id != payment.p_id:
     147        msg = _('Response transaction id does not match.')
     148        log = 'wrong response for %s payment %s: %s' % (
     149            payment.p_category, payment.p_id, str(form))
     150        payment.p_state = 'failed'
     151        notify(grok.ObjectModifiedEvent(payment))
     152        return False, msg, log
     153    payment.p_state = 'paid'
     154    if not verify:
     155        payment.payment_date = datetime.utcnow()
     156    msg = _('Successful response received')
     157    log = 'valid response for %s payment %s: %s' % (
     158        payment.p_category, payment.p_id, str(form))
     159    notify(grok.ObjectModifiedEvent(payment))
     160    return True, msg, log
  • main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/tests.py

    r15586 r15589  
    2121import json
    2222import hashlib
     23import httplib
     24from urllib import urlencode
    2325from datetime import datetime, timedelta, date
    2426from zope.component import createObject, getUtility
     
    3133from kofacustom.nigeria.testing import FunctionalLayer
    3234from kofacustom.nigeria.etranzact.helpers import (
    33     get_query_response, get_caller_response)
     35    query_history,)
    3436
    3537#from kofacustom.nigeria.etranzact.helpers import (query_etranzact)
     
    5759    return func
    5860
     61def post_caller(host, https, terminal_id, transaction_id, responseurl,
     62                        amount_auth, email, phone, display_fullname, hashvalue,
     63                        logo_url):
     64    headers={"Content-type": "application/x-www-form-urlencoded",
     65             "Accept": "text/plain"}
     66    url = "/webconnect/v3/caller.jsp"
     67    if https:
     68        h = httplib.HTTPSConnection(host)
     69    else:
     70        h = httplib.HTTPConnection(host)
     71    args = {'TERMINAL_ID': terminal_id,
     72            'TRANSACTION_ID': transaction_id,
     73            'RESPONSE_URL': responseurl,
     74            'AMOUNT': amount_auth,
     75            'EMAIL': email,
     76            'PHONENO': phone,
     77            'FULL_NAME': display_fullname,
     78            'CURRENCY_CODE': 'NGN',
     79            'CHECKSUM': hashvalue,
     80            'LOGO_URL': logo_url,
     81            }
     82    h.request('POST', url, urlencode(args), headers)
     83    return
     84    response = h.getresponse()
     85    if response.status!=200:
     86        return 'Connection error (%s, %s)' % (response.status, response.reason)
     87    resp = response.read()
     88    return resp
     89
     90def create_transaction(transaction_id):
     91    responseurl = 'http://xxxx'
     92    amount = '4444.0'
     93    email = 'aa@aa.ng'
     94    phone = '12324'
     95    display_fullname = 'Tester'
     96    logo_url = 'http://xxxx'
     97    hashargs =  amount + TERMINAL_ID + transaction_id \
     98        + responseurl + 'DEMO_KEY'
     99    hashvalue = hashlib.md5(hashargs).hexdigest()
     100    response = post_caller(HOST, HTTPS, TERMINAL_ID,
     101                         transaction_id, responseurl,
     102                         amount, email, phone,
     103                         display_fullname, hashvalue,
     104                         logo_url)
     105    return response
     106
     107
    59108class HelperTests(unittest.TestCase):
    60109
    61110    terminal_id = TERMINAL_ID
    62111
    63     def _create_transaction(self, transaction_id):
    64         responseurl = 'http://xxxx'
    65         amount = '4444.0'
    66         email = 'aa@aa.ng'
    67         phone = '12324'
    68         display_fullname = 'Tester'
    69         logo_url = 'http://xxxx'
    70         hashargs =      amount + self.terminal_id + transaction_id \
    71             + responseurl + 'DEMO_KEY'
    72         hashvalue = hashlib.md5(hashargs).hexdigest()
    73         response = get_caller_response(HOST, HTTPS, self.terminal_id,
    74                                        transaction_id, responseurl,
    75                                        amount, email, phone,
    76                                        display_fullname, hashvalue,
    77                                        logo_url)
    78         return response
    79 
    80112    @external_test
    81     def test_query_etranzact(self):
     113    def test_query_history(self):
    82114        transaction_id = str(random.randint(100000000, 999999999))
    83         response = get_query_response(HOST, self.terminal_id,
    84                                 transaction_id, HTTPS)
     115        response = query_history(HOST, self.terminal_id,
     116                                transaction_id, HTTPS, 'http://xxxxx')
    85117        self.assertEqual(
    86118            response,
     
    88120            % transaction_id)
    89121        # Okay, let's create a transaction
    90         caller_response = self._create_transaction(transaction_id)
     122        caller_response = create_transaction(transaction_id)
    91123        self.assertEqual(caller_response, None)
    92124        # It seems that the transaction has been created but we don't get a
    93125        # useful response
    94         query_response = get_query_response(HOST, self.terminal_id,
    95                                 transaction_id, HTTPS)
     126        query_response = query_history(HOST, self.terminal_id,
     127                                transaction_id, HTTPS, 'http://xxxxx')
    96128        self.assertEqual(query_response, '')
    97129        # The same, an 'empty' response obviously means that the transaction
    98         # was found. The result was probably sent to the response_url.
     130        # was found. The result was  sent to the response_url (see below).
     131        # We need browser tests.
    99132        return
    100133
     
    126159
    127160    @external_test
    128     def test_applicant_etranzact_form(self):
    129         # Manager can access Etranzact form
     161    def test_views(self):
     162        # Manager can access eTranzact form
    130163        self.browser.getLink("Pay via eTranzact").click()
    131164        self.assertTrue("Pay now" in self.browser.contents)
    132         # Means of testing end here.
     165        # Means of testing end here. We have to manually
     166        # create an eTranzact transaction.
     167        logo_url = 'http://xxxx'
     168        responseurl = self.payment_url + '/receive_etranzact'
     169        amount = "%.1f" % self.payment.amount_auth
     170        customer = self.applicant
     171        hashargs =      amount + TERMINAL_ID + self.payment.p_id \
     172            + responseurl + 'DEMO_KEY'
     173        hashvalue = hashlib.md5(hashargs).hexdigest()
     174        post_caller(HOST, HTTPS, TERMINAL_ID,
     175                   self.payment.p_id, responseurl,
     176                   self.payment.amount_auth, customer.email,
     177                   customer.phone,
     178                   customer.display_fullname, hashvalue,
     179                   logo_url)
    133180        return
    134181
Note: See TracChangeset for help on using the changeset viewer.