source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/tests.py @ 17808

Last change on this file since 17808 was 17783, checked in by Henrik Bettermann, 6 months ago

Use serviceCode.

  • Property svn:keywords set to Id
File size: 19.4 KB
Line 
1## $Id: tests.py 17783 2024-05-14 08:46:27Z henrik $
2##
3## Copyright (C) 2017 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import os
19import unittest
20import random
21import json
22import hashlib
23import httplib
24from urllib import urlencode
25from datetime import datetime, timedelta, date
26from zope.component import createObject, getUtility
27from zope.catalog.interfaces import ICatalog
28from hurry.workflow.interfaces import IWorkflowState
29from waeup.kofa.students.tests.test_browser import StudentsFullSetup
30from waeup.kofa.applicants.tests.test_browser import ApplicantsFullSetup
31from waeup.kofa.configuration import SessionConfiguration
32from kofacustom.nigeria.students.payments import NigeriaStudentOnlinePayment
33from kofacustom.nigeria.testing import FunctionalLayer
34from kofacustom.nigeria.etranzact.helpers import (
35    query_history, query_payoutlet, ERROR_PART1, ERROR_PART2,
36    )
37
38#from kofacustom.nigeria.etranzact.helpers import (query_etranzact)
39
40# Also run tests that send requests to external servers?
41#   If you enable this, please make sure the external services
42#   do exist really and are not bothered by being spammed by a test programme.
43
44EXTERNAL_TESTS = False
45
46TERMINAL_ID = '5003021194'
47HOST = 'demo.etranzactng.com'
48HTTPS = True
49SECRET_KEY = 'DEMO_KEY'
50LOGO_URL = 'https://iuokada.waeup.org/static_custom/iou_logo.png'
51GATEWAY_AMT = 500.0
52
53# Valid transaction id in Etranzact system
54TID = 'p5689785145198'
55
56def external_test(func):
57    if not EXTERNAL_TESTS:
58        myself = __file__
59        if myself.endswith('.pyc'):
60            myself = myself[:-1]
61        print "WARNING: external tests are skipped!"
62        print "WARNING: edit %s to enable them." % myself
63        return
64    return func
65
66def post_caller(host, https, terminal_id, transaction_id, responseurl,
67                        amount_auth, email, phone, display_fullname, hashvalue,
68                        logo_url):
69    headers={"Content-type": "application/x-www-form-urlencoded",
70             "Accept": "text/plain"}
71    url = "/webconnect/v3/caller.jsp"
72    if https:
73        h = httplib.HTTPSConnection(host)
74    else:
75        h = httplib.HTTPConnection(host)
76    args = {'TERMINAL_ID': terminal_id,
77            'TRANSACTION_ID': transaction_id,
78            'RESPONSE_URL': responseurl,
79            'AMOUNT': amount_auth,
80            'EMAIL': email,
81            'PHONENO': phone,
82            'FULL_NAME': display_fullname,
83            'CURRENCY_CODE': 'NGN',
84            'CHECKSUM': hashvalue,
85            'LOGO_URL': logo_url,
86            }
87    h.request('POST', url, urlencode(args), headers)
88    return
89    response = h.getresponse()
90    if response.status!=200:
91        return 'Connection error (%s, %s)' % (response.status, response.reason)
92    resp = response.read()
93    return resp
94
95def create_transaction(transaction_id):
96    responseurl = 'http://xxxx'
97    amount = '4444.0'
98    email = 'aa@aa.ng'
99    phone = '12324'
100    display_fullname = 'Tester'
101    logo_url = 'http://xxxx'
102    hashargs =  amount + TERMINAL_ID + transaction_id \
103        + responseurl + 'DEMO_KEY'
104    hashvalue = hashlib.md5(hashargs).hexdigest()
105    response = post_caller(HOST, HTTPS, TERMINAL_ID,
106                         transaction_id, responseurl,
107                         amount, email, phone,
108                         display_fullname, hashvalue,
109                         logo_url)
110    return response
111
112
113class HelperTests(unittest.TestCase):
114
115    terminal_id = TERMINAL_ID
116
117    @external_test
118    def test_query_history(self):
119        transaction_id = str(random.randint(100000000, 999999999))
120        raw, formvars = query_history(HOST, self.terminal_id,
121                                transaction_id, HTTPS)
122        self.assertTrue(
123            'Transaction with the given transaction_id (%s) not found'
124            % transaction_id in raw)
125        # Okay, let's create a transaction
126        caller_response = create_transaction(transaction_id)
127        self.assertEqual(caller_response, None)
128        # It seems that the transaction has been created but we don't get a
129        # useful response
130        raw, formvars = query_history(HOST, self.terminal_id,
131                                transaction_id, HTTPS)
132        self.assertTrue(
133            '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"\r\n    '
134            '"http://www.w3.org/TR/html4/loose.dtd">' in raw)
135        # The same, an 'empty' response obviously means that the transaction
136        # was found but no result was  sent to the response_url because the
137        # payment was cancelled.
138
139        # Peter: No response would be returned because payment status information
140        # was not saved. Whenever you get a null response, means payment was
141        # not received only payments with error code 0 is successful.
142        # So in this case transaction fails.
143
144        # We manually created and tried to pay a transaction
145        # which seems to be valid till next restart of the demo portal.
146        raw, formvars = query_history(HOST, self.terminal_id, TID, HTTPS)
147        # Now Etranzact is redirecting but the response is still useless
148        self.assertTrue('Redirecting...' in raw)
149        self.assertEqual(formvars['TRANSACTION_ID'], TID)
150        return
151
152    @external_test
153    def test_query_payoutlet(self):
154        # We've got some test numbers from Etranzact for testing
155        payment = NigeriaStudentOnlinePayment()
156        payment.p_id = 'p5723474039401'
157        success, msg, log = query_payoutlet(
158            HOST, '5003021194', '500854291572447457669', payment, True)
159        self.assertTrue(msg, 'Wrong amount')
160        payment.amount_auth = 200000.0
161        success, msg, log = query_payoutlet(
162            HOST, '5003021194', '500854291572447457669', payment, True)
163        self.assertTrue(success)
164        payment.p_id = 'xyz'
165        success, msg, log = query_payoutlet(
166            HOST, '5003021194', '500854291572447457669', payment, True)
167        self.assertTrue(msg, 'Wrong payment id')
168        return
169
170
171
172class EtranzactTestsApplicants(ApplicantsFullSetup):
173    """Tests for the Etranzact payment gateway.
174    """
175
176    layer = FunctionalLayer
177
178    def setUp(self):
179        super(EtranzactTestsApplicants, self).setUp()
180        configuration = SessionConfiguration()
181        configuration.academic_session = datetime.now().year - 2
182        configuration.etranzact_webconnect_enabled = True
183        configuration.etranzact_payoutlet_enabled = True
184        self.app['configuration'].addSessionConfiguration(configuration)
185        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
186        self.browser.open(self.manage_path)
187        #IWorkflowState(self.student).setState('started')
188        super(EtranzactTestsApplicants, self).fill_correct_values()
189        self.applicantscontainer.application_fee = 3333.0
190        self.browser.getControl(name="form.nationality").value = ['NG']
191        self.browser.getControl(name="transition").value = ['start']
192        self.browser.getControl("Save").click()
193        self.browser.getControl("Add online").click()
194        self.assertMatches('...ticket created...',
195                           self.browser.contents)
196        self.payment = self.applicant.values()[0]
197        self.payment_url = self.browser.url
198
199    @external_test
200    def test_applicant_views(self):
201        # Manager can access Etranzact form
202        self.browser.getLink("Pay via Etranzact WebConnect").click()
203        self.assertTrue("Pay now" in self.browser.contents)
204        # Means of testing end here.
205        # We requery an existing paiment now.
206        self.payment.p_id = TID
207        self.browser.open(self.payment_url)
208        self.browser.getLink("Requery Etranzact WebConnect History").click()
209        self.assertTrue('Wrong checksum.' in self.browser.contents)
210        # ... probably because responseurl of the transaction stored in the
211        # system and the responseurl generated in process_response are
212        # different
213        # Means of testing end here again.
214        return
215
216class EtranzactTestsStudents(StudentsFullSetup):
217    """Tests for the Etranzact payment gateway.
218    """
219
220    layer = FunctionalLayer
221
222    def setUp(self):
223        super(EtranzactTestsStudents, self).setUp()
224        self.app['configuration']['2004'].etranzact_webconnect_enabled = True
225        self.app['configuration']['2004'].etranzact_payoutlet_enabled = True
226        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
227        self.browser.open(self.payments_path)
228        IWorkflowState(self.student).setState('cleared')
229        self.student.nationality = u'NG'
230        self.browser.open(self.payments_path + '/addop')
231        self.browser.getControl(name="form.p_category").value = ['schoolfee']
232        self.browser.getControl("Create ticket").click()
233        self.assertMatches('...ticket created...',
234                           self.browser.contents)
235        self.browser.open(self.payments_path)
236        ctrl = self.browser.getControl(name='val_id')
237        self.value = ctrl.options[0]
238        self.browser.getLink(self.value).click()
239        self.assertMatches('...Amount Authorized...',
240                           self.browser.contents)
241        self.assertTrue('<span>40000.0</span>', self.browser.contents)
242        self.payment_url = self.browser.url
243        self.payment = self.student['payments'][self.value]
244
245    @external_test
246    def test_student_views(self):
247        # Manager can access Etranzact form
248        self.browser.getLink("Pay via Etranzact WebConnect").click()
249        self.assertTrue("Pay now" in self.browser.contents)
250        # Means of testing end here.
251        # We requery an existing paiment now.
252        self.payment.p_id = TID
253        self.browser.open(self.payment_url)
254        self.browser.getLink("Requery Etranzact WebConnect History").click()
255        self.assertTrue('Wrong checksum.' in self.browser.contents)
256        # ... probably because responseurl and amount stored in the
257        # system and the responseurl generated in process_response are
258        # different
259        # Means of testing end here again.
260        return
261
262    @external_test
263    def test_student_payoutlet_views(self):
264        self.browser.getLink("Pay via Etranzact PayOutlet").click()
265        self.browser.getControl(name="confirmation_number").value = '600854291572447457669'
266        self.browser.getControl("Requery now").click()
267        # This response is strange
268        self.assertTrue('-3:Wrong Setup' in self.browser.contents)
269        self.browser.getLink("Pay via Etranzact PayOutlet").click()
270        # This confirmation number exists
271        self.browser.getControl(name="confirmation_number").value = '500854291572447457669'
272        self.browser.getControl("Requery now").click()
273        self.assertTrue('Wrong amount' in self.browser.contents)
274        # Some attributes have been set
275        self.assertEqual(self.payment.r_desc, 'Test Test Test-CLEARANCE -001-p5723474039401')
276        return
277
278    def test_webservice(self):
279        self.browser.open(
280            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOLFEE'
281            % self.payment.p_id)
282        self.assertEqual(self.browser.contents,
283            'PayeeName=Anna Tester~'
284            'Faculty=fac1~Department=dep1~'
285            'Level=100~ProgrammeType=CERT1~'
286            'StudyType=ug_ft~Session=2004/2005~'
287            'PayeeID=%s~'
288            'Amount=40000.0~FeeStatus=unpaid~'
289            'Semester=N/A~PaymentType=School Fee~'
290            'MatricNumber=234~Email=aa@aa.ng~'
291            'PhoneNumber=1234' % self.payment.p_id)
292        self.browser.open('http://localhost/app/feerequest')
293        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Missing PAYEE_ID' + ERROR_PART2)
294
295        self.browser.open('http://localhost/app/feerequest?NONSENSE=nonsense')
296        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Missing PAYEE_ID' + ERROR_PART2)
297
298        self.browser.open(
299            'http://localhost/app/feerequest?PAYEE_ID=nonsense&PAYMENT_TYPE=SCHOOLFEE')
300        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Invalid PAYEE_ID' + ERROR_PART2)
301
302        self.browser.open(
303            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=NONSENSE'
304            % self.payment.p_id)
305        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Invalid PAYMENT_TYPE' + ERROR_PART2)
306
307        self.browser.open(
308            'http://localhost/app/feerequest?PAYEE_ID=%s' % self.payment.p_id)
309        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Invalid PAYMENT_TYPE' + ERROR_PART2)
310
311        self.browser.open(
312            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=CLEARANCE'
313            % self.payment.p_id)
314        self.assertEqual(self.browser.contents, ERROR_PART1 + 'Wrong PAYMENT_TYPE' + ERROR_PART2)
315
316        # Change payment state
317        self.student['payments'][self.payment.p_id].p_state = 'paid'
318
319        self.browser.open(
320            'http://localhost/app/feerequest?PAYEE_ID=%s&PAYMENT_TYPE=SCHOOLFEE'
321            % self.payment.p_id)
322        self.assertEqual(self.browser.contents, ERROR_PART1 + 'PAYEE_ID already used' + ERROR_PART2)
323
324# Credo tests
325
326from kofacustom.nigeria.etranzact.helpers import (
327    query_credo_payment, get_JSON_response_initialize)
328
329SECRET_API_KEY = "0PRI0500LB11cBSSLcW0DcW1BcWgmf45"
330API_PUBLIC_KEY = "0PUB0500wuoOe9sdtSOLj5peqHKc8Q9W"
331EXTERNAL_TESTS_CREDO = True
332CREDO_HOST = "api.credodemo.com"
333
334def external_test_credo(func):
335    if not EXTERNAL_TESTS_CREDO:
336        myself = __file__
337        if myself.endswith('.pyc'):
338            myself = myself[:-1]
339        print "WARNING: external Credo tests are skipped!"
340        print "WARNING: edit %s to enable them." % myself
341        return
342    return func
343
344class CredoTestsStudents(StudentsFullSetup):
345
346    layer = FunctionalLayer
347
348    P_ID = 'p7120340727304' # works only if such a payment was made on the test platform
349
350    def setUp(self):
351        super(CredoTestsStudents, self).setUp()
352        self.app['configuration']['2004'].etranzact_credo_enabled = True
353        payment = createObject('waeup.StudentOnlinePayment')
354        payment.p_id = self.P_ID
355        payment.p_category = 'schoolfee'
356        payment.amount_auth = 100000.0
357        self.student['payments'][payment.p_id] = payment
358        self.payment2 = payment
359
360    @external_test_credo
361    def test_initialize(self):
362
363        public_api_key = API_PUBLIC_KEY
364        callbackUrl = 'aa.aa.aa'
365        response = get_JSON_response_initialize(self.payment2, CREDO_HOST, callbackUrl, public_api_key, None)
366
367        ## A typical response
368
369        #{u'status': 200,
370        # u'execTime': 5.109764,
371        # u'message': u'Successfully processed',
372        # u'data':
373        #    {u'credoReference': u'vsb200B5oM0521Mb00og',
374        #     u'reference': u'xyz',
375        #     u'authorizationUrl': u'https://pay.credodemo.com/vsb200B5oM0521Mb00og'
376        #     },
377        # u'error': []
378        #}
379
380        # Payment already exists
381        self.assertEqual(response, {'error': u'Reference must be unique. '})
382
383        #self.assertEqual(response['status'], 200)
384        #self.assertEqual(response['message'], 'Successfully processed')
385        #self.assertEqual(response['data']['reference'], self.P_ID)
386        #self.assertTrue('https://pay.credodemo.com/' in response['data']['authorizationUrl'])
387        return
388
389    @external_test_credo
390    def test_verify(self):
391        self.payment2.p_id = 'anything'
392        success, msg, log = query_credo_payment(self.payment2, CREDO_HOST, SECRET_API_KEY)
393        self.assertEqual(log, 'Transaction with ref# anything not found')
394        self.payment2.p_id = self.P_ID # manually paid
395        success, msg, log = query_credo_payment(self.payment2, CREDO_HOST, SECRET_API_KEY)
396        self.assertEqual(msg, 'Successful callback received')
397        self.assertEqual(self.payment2.r_code, '0')
398        self.assertEqual(self.payment2.r_desc, 'Successfully processed')
399        self.assertEqual(self.payment2.p_state, 'paid')
400        return
401
402    @external_test_credo
403    def test_student_credo_views(self):
404        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
405        self.browser.open(self.payments_path)
406        self.browser.getLink(self.P_ID).click()
407        self.browser.getLink("Requery Etranzact Credo").click()
408        self.assertTrue('<span>Successfully processed</span>' in self.browser.contents)
409        self.assertEqual(self.payment2.r_desc, 'Successfully processed')
410        return
411
412class CredoTestsApplicants(ApplicantsFullSetup):
413
414    layer = FunctionalLayer
415
416    P_ID = 'p7120808915674' # works only if such a payment was made on the test platform
417
418    def setUp(self):
419        super(CredoTestsApplicants, self).setUp()
420        # Add session configuration object
421        configuration = SessionConfiguration()
422        configuration.academic_session =  self.applicant.__parent__.year
423        configuration.etranzact_credo_enabled = True
424        self.app['configuration'].addSessionConfiguration(configuration)
425        payment = createObject('waeup.ApplicantOnlinePayment')
426        payment.p_id = self.P_ID
427        payment.p_category = 'application'
428        payment.amount_auth = 5000.0
429        self.applicant.email = 'xx@xx.xx'
430        self.applicant[payment.p_id] = payment
431        self.payment2 = payment
432
433    @external_test_credo
434    def test_initialize(self):
435
436        public_api_key = API_PUBLIC_KEY
437        callbackUrl = 'aa.aa.aa'
438        response = get_JSON_response_initialize(self.payment2, CREDO_HOST, callbackUrl, public_api_key, None)
439
440        # Payment already exists
441        self.assertEqual(response, {'error': u'Reference must be unique. '})
442
443        #self.assertEqual(response['status'], 200)
444        #self.assertEqual(response['message'], 'Successfully processed')
445        #self.assertEqual(response['data']['reference'], self.P_ID)
446        #self.assertTrue('https://pay.credodemo.com/' in response['data']['authorizationUrl'])
447        return
448
449    @external_test_credo
450    def test_verify(self):
451        self.payment2.p_id = 'anything'
452        success, msg, log = query_credo_payment(self.payment2, CREDO_HOST, SECRET_API_KEY)
453        self.assertEqual(log, 'Transaction with ref# anything not found')
454        self.payment2.p_id = self.P_ID # manually paid
455        success, msg, log = query_credo_payment(self.payment2, CREDO_HOST, SECRET_API_KEY)
456        self.assertEqual(msg, 'Successful callback received')
457        self.assertEqual(self.payment2.r_code, '0')
458        self.assertEqual(self.payment2.r_desc, 'Successfully processed')
459        self.assertEqual(self.payment2.p_state, 'paid')
460        return
461
462    @external_test_credo
463    def test_applicant_credo_views(self):
464        IWorkflowState(self.applicant).setState('started')
465        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
466        self.browser.open(self.view_path)
467        self.browser.getLink(self.P_ID).click()
468        self.browser.getLink("Requery Etranzact Credo").click()
469        self.assertTrue('<span>Successfully processed</span>' in self.browser.contents)
470        self.assertEqual(self.payment2.r_desc, 'Successfully processed')
471        self.assertEqual(self.applicant.state, 'paid')
472        return
Note: See TracBrowser for help on using the repository browser.