source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/interswitch/tests.py @ 16484

Last change on this file since 16484 was 16484, checked in by Henrik Bettermann, 3 years ago

Implement PAYDirect Bank Branch payment.

  • Property svn:keywords set to Id
File size: 17.7 KB
Line 
1## $Id: tests.py 16484 2021-05-19 07:47:21Z henrik $
2##
3## Copyright (C) 2011 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
19from datetime import datetime, timedelta, date
20from zope.component import createObject, getUtility
21from zope.catalog.interfaces import ICatalog
22from xml.dom.minidom import parseString
23from hurry.workflow.interfaces import IWorkflowState
24from waeup.kofa.students.tests.test_browser import StudentsFullSetup
25from waeup.kofa.applicants.tests.test_browser import ApplicantsFullSetup
26from waeup.kofa.configuration import SessionConfiguration
27from waeup.kofa.students.payments import StudentOnlinePayment
28from waeup.kofa.browser.tests.test_pdf import samples_dir
29from kofacustom.nigeria.interswitch.helpers import (
30    query_interswitch, get_SOAP_response_paydirect, SOAP_post)
31from kofacustom.nigeria.testing import FunctionalLayer
32
33# Also run tests that send requests to external servers?
34#   If you enable this, please make sure the external services
35#   do exist really and are not bothered by being spammed by a test programme.
36EXTERNAL_TESTS_1 = True
37EXTERNAL_TESTS_2 = True
38
39PAYDIRECT_HOST = 'sandbox.interswitchng.com'
40PAYDIRECT_URL = '/bookonhold/bookonhold.asmx'
41MERCHANT_ID = '6033'
42
43def external_test_1(func):
44    if not EXTERNAL_TESTS_1:
45        myself = __file__
46        if myself.endswith('.pyc'):
47            myself = myself[:-1]
48        print "WARNING: external tests are skipped!"
49        print "WARNING: edit %s to enable them." % myself
50        return
51    return func
52
53def external_test_2(func):
54    if not EXTERNAL_TESTS_2:
55        myself = __file__
56        if myself.endswith('.pyc'):
57            myself = myself[:-1]
58        print "WARNING: external tests are skipped!"
59        print "WARNING: edit %s to enable them." % myself
60        return
61    return func
62
63class InterswitchTestsStudents(StudentsFullSetup):
64    """Tests for the Interswitch payment gateway.
65    """
66
67    layer = FunctionalLayer
68
69    def setUp(self):
70        super(InterswitchTestsStudents, self).setUp()
71        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
72        self.browser.open(self.payments_path)
73        IWorkflowState(self.student).setState('cleared')
74        self.student.nationality = u'NG'
75        self.browser.open(self.payments_path + '/addop')
76        self.browser.getControl(name="form.p_category").value = ['schoolfee']
77        self.browser.getControl("Create ticket").click()
78        self.assertMatches('...ticket created...',
79                           self.browser.contents)
80        self.browser.open(self.payments_path)
81        ctrl = self.browser.getControl(name='val_id')
82        self.value = ctrl.options[0]
83        self.browser.getLink(self.value).click()
84        self.assertMatches('...Amount Authorized...',
85                           self.browser.contents)
86        self.assertTrue('<span>40000.0</span>', self.browser.contents)
87        self.payment_url = self.browser.url
88        self.payment = self.student['payments'][self.value]
89
90    def test_interswitch_form(self):
91        # Manager can access InterswitchForm
92        self.browser.getLink("Pay via Interswitch CollegePAY", index=0).click()
93        self.assertMatches('...<input type="hidden" name="pay_item_id" />...',
94                           self.browser.contents)
95        self.assertMatches('...Total Amount Authorized:...',
96                           self.browser.contents)
97        self.assertEqual(self.student.current_mode, 'ug_ft')
98        self.assertMatches(
99            '...<input type="hidden" name="amount" value="4000000" />...',
100            self.browser.contents)
101
102        # Create school fee ticket for returning students. Payment is made
103        # for next session.
104        current_payment_key = self.student['payments'].keys()[0]
105        self.certificate.study_mode = u'ug_pt'
106        IWorkflowState(self.student).setState('returning')
107        configuration = createObject('waeup.SessionConfiguration')
108        configuration.academic_session = 2005
109        self.app['configuration'].addSessionConfiguration(configuration)
110        self.browser.open(self.payments_path + '/addop')
111        self.browser.getControl(name="form.p_category").value = ['schoolfee']
112        self.browser.getControl("Create ticket").click()
113        self.browser.open(self.payments_path)
114        ctrl = self.browser.getControl(name='val_id')
115        value = ctrl.options[1]
116        self.assertEqual(self.student['payments'][value].provider_amt, 0.0)
117        self.assertEqual(self.student['payments'][value].gateway_amt, 0.0)
118        self.browser.getLink(value).click()
119        self.browser.getLink("Pay via Interswitch CollegePAY", index=0).click()
120        # Split amounts have been set.
121        self.assertEqual(self.student['payments'][value].provider_amt, 0.0)
122        self.assertEqual(self.student['payments'][value].gateway_amt, 300.0)
123        self.assertMatches('...<input type="hidden" name="pay_item_id" />...',
124                           self.browser.contents)
125        self.assertTrue(
126            '<input type="hidden" name="amount" value="2030000" />' in
127            self.browser.contents)
128
129    def test_interswitch_form_ticket_expired(self):
130        # Manager can access InterswitchForm
131        self.browser.getLink("Pay via Interswitch CollegePAY", index=0).click()
132        self.assertMatches('...<input type="hidden" name="pay_item_id" />...',
133                           self.browser.contents)
134        self.assertMatches('...Total Amount Authorized:...',
135                           self.browser.contents)
136        self.assertEqual(self.student.current_mode, 'ug_ft')
137        self.assertTrue(
138            '<input type="hidden" name="amount" value="4030000" />' in
139            self.browser.contents)
140        delta = timedelta(days=8)
141        self.payment.creation_date -= delta
142        self.browser.open(self.payment_url)
143        self.browser.getLink("Pay via Interswitch CollegePAY", index=0).click()
144        self.assertMatches(
145            '...This payment ticket is too old. Please create a new ticket...',
146            self.browser.contents)
147        delta = timedelta(days=2)
148        self.payment.creation_date += delta
149        self.browser.open(self.payment_url)
150        self.browser.getLink("Pay via Interswitch CollegePAY").click()
151        self.assertMatches('...Total Amount Authorized:...',
152                           self.browser.contents)
153
154    def test_interswitch_form_ticket_expired_tz(self):
155        # The form copes with timezones when calculating expirements.
156        # We should not have TZ data in timestamps processed, but it looks
157        # like we get some with imports :-/
158        self.browser.getLink("Pay via Interswitch CollegePAY", index=0).click()
159        delta = timedelta(days=8)
160        self.payment.creation_date -= delta
161        from pytz import timezone
162        self.payment.creation_date = timezone("Europe/Berlin").localize(
163            self.payment.creation_date)
164        self.browser.open(self.payment_url)
165        self.browser.getLink("Pay via Interswitch CollegePAY", index=0).click()
166        self.assertMatches(
167            '...This payment ticket is too old. Please create a new ticket...',
168            self.browser.contents)
169        delta = timedelta(days=2)
170        self.payment.creation_date += delta
171        self.browser.open(self.payment_url)
172        self.browser.getLink("Pay via Interswitch CollegePAY").click()
173        self.assertMatches('...Total Amount Authorized:...',
174                           self.browser.contents)
175
176    @external_test_1
177    def test_query_interswitch_SOAP(self):
178        host = 'webpay.interswitchng.com'
179        url = '/paydirect/services/TransactionQueryWs.asmx'
180        https = True
181        mac = None
182        product_id = '5845' # AAUE regular
183        payment = StudentOnlinePayment()
184        payment.p_id ='p4465649308559'
185        payment.amount_auth = 60250.0
186        success, msg, log = query_interswitch(
187            payment, product_id, host, url, https, mac, False)
188        self.assertEqual('Successful callback received.', msg)
189        self.assertTrue(success)
190        self.assertTrue(
191            '00:Approved Successful:6025000:3154:p4465649308559:'
192            'ZIB|WEB|ABAL|3-11-2015|021336:000457580882' in log)
193
194    @external_test_1
195    def test_query_interswitch_JSON(self):
196        host = 'webpay.interswitchng.com'
197        url = '/paydirect/api/v1/gettransaction.json'
198        mac = '9718FA00B0F5070B388A9896ADCED9B2FB02D30F71E12E68BDADC63F6852A3496FF97D8A0F9DA9F753B911A49BB09BB87B55FD02046BD325C74C46C0123CF023'
199        https = True
200        product_id = '5845' # AAUE regular
201        payment = StudentOnlinePayment()
202        payment.p_id ='p4465649308559'
203        payment.amount_auth = 1.0
204        success, msg, log = query_interswitch(
205            payment, product_id, host, url, https, mac, False)
206        self.assertFalse(success)
207        self.assertTrue('Unsuccessful callback:' in msg)
208        self.assertTrue('Amount Inconsistency' in log)
209        payment.amount_auth = 60250.0
210        success, msg, log = query_interswitch(
211            payment, product_id, host, url, https, mac, False)
212        self.assertEqual('Successful callback received', msg)
213        self.assertTrue(success)
214        self.assertTrue(
215            "{u'SplitAccounts': [], "
216            "u'MerchantReference': u'p4465649308559', "
217            "u'PaymentReference': u'ZIB|WEB|ABAL|3-11-2015|021336', "
218            "u'TransactionDate': u'2015-11-03T16:40:54.487', "
219            "u'RetrievalReferenceNumber': u'000457580882', "
220            "u'ResponseDescription': u'Approved Successful', "
221            "u'Amount': 6025000, "
222            "u'CardNumber': u'3154', "
223            "u'ResponseCode': u'00', "
224            "u'LeadBankCbnCode': None, "
225            "u'LeadBankName': None}" in log)
226
227# PAYDirect tests
228
229    def create_booking(self, p_id):
230        xml="""\
231<?xml version="1.0" encoding="utf-8"?>
232<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
233  <soap:Body>
234    <CreateBooking xmlns="http://interswitchng.com/bookonhold">
235      <ReservationRequest>
236        <MerchantId>%s</MerchantId>
237        <Bookings>
238          <Booking>
239            <ReferenceNumber>%s%s</ReferenceNumber>
240            <ResponseCode>01</ResponseCode>
241            <ResponseDescription>02</ResponseDescription>
242            <Description>My Description</Description>
243            <Amount>1000</Amount>
244            <DateBooked>2021-05-05</DateBooked>
245            <DateExpired>2025-05-05</DateExpired>
246            <FirstName>Dummy</FirstName>
247            <LastName>Student</LastName>
248            <Status>string</Status>
249            <PaymentStatus>string</PaymentStatus>
250            <PaymentReference>string</PaymentReference>
251            <ChannelName>04</ChannelName>
252            <TerminalId>05</TerminalId>
253            <Location>string</Location>
254            <PaymentDate>2020-05-05</PaymentDate>
255            <PaymentMethod>string</PaymentMethod>
256            <Email>aa@aa.aa</Email>
257            <ItemCode>01</ItemCode>
258          </Booking>
259        </Bookings>
260      </ReservationRequest>
261    </CreateBooking>
262  </soap:Body>
263</soap:Envelope>""" % (MERCHANT_ID, MERCHANT_ID, p_id[1:])
264
265        SOAP_post("http://interswitchng.com/bookonhold/CreateBooking",xml,
266                  PAYDIRECT_HOST, PAYDIRECT_URL, True)
267
268    @external_test_2
269    def test_get_SOAP_response_paydirect(self):
270        p_id = 'p6021570467807'
271        self.create_booking(p_id)
272        result_xml = get_SOAP_response_paydirect(
273            MERCHANT_ID, p_id, PAYDIRECT_HOST, PAYDIRECT_URL, True)
274        doc=parseString(result_xml)
275        status=doc.getElementsByTagName('PaymentStatus')[0].firstChild.data
276        amount=doc.getElementsByTagName('Amount')[0].firstChild
277        self.assertEqual(status, 'Pending')
278        self.assertEqual(amount, None)
279        p_id = 'p5812734587097'
280        result_xml = get_SOAP_response_paydirect(MERCHANT_ID, p_id, PAYDIRECT_HOST, PAYDIRECT_URL, True)
281        doc=parseString(result_xml)
282        self.assertEqual(doc.getElementsByTagName('PaymentStatus'), [])
283
284    @external_test_2
285    def test_paydirect(self):
286        # Manager can access InterswitchForm
287        self.browser.getLink("Pay via Interswitch PAYDirect").click()
288        self.assertMatches('...Total Amount Authorized:...',
289                           self.browser.contents)
290        self.assertEqual(self.student.current_mode, 'ug_ft')
291        # Create school fee ticket for returning students. Payment is made
292        # for next session.
293        current_payment_key = self.student['payments'].keys()[0]
294        self.certificate.study_mode = u'ug_pt'
295        IWorkflowState(self.student).setState('returning')
296        configuration = createObject('waeup.SessionConfiguration')
297        configuration.academic_session = 2005
298        self.app['configuration'].addSessionConfiguration(configuration)
299        self.browser.open(self.payments_path + '/addop')
300        self.browser.getControl(name="form.p_category").value = ['schoolfee']
301        self.browser.getControl("Create ticket").click()
302        self.browser.open(self.payments_path)
303        ctrl = self.browser.getControl(name='val_id')
304        value = ctrl.options[1]
305        self.assertEqual(self.student['payments'][value].provider_amt, 0.0)
306        self.assertEqual(self.student['payments'][value].gateway_amt, 0.0)
307        self.browser.getLink(value).click()
308        self.browser.getLink("Pay via Interswitch PAYDirect").click()
309        # Split amounts have been set.
310        self.assertEqual(self.student['payments'][value].provider_amt, 0.0)
311        self.assertEqual(self.student['payments'][value].gateway_amt, 300.0)
312        # Reference number has not yet been saved but can be seen in browser
313        self.assertEqual(self.student['payments'][value].r_pay_reference, None)
314        ref_number = '%s%s' % (MERCHANT_ID,value[1:])
315        self.assertTrue(ref_number in self.browser.contents)
316        self.browser.getControl("Requery").click()
317        self.assertTrue('Your payment %s was not found.' % value in self.browser.contents)
318        self.create_booking(value)
319        self.browser.getLink("Pay via Interswitch PAYDirect").click()
320        self.browser.getControl("Requery").click()
321        self.assertTrue('pending' in self.browser.contents)
322        # Reference number has still not been saved because the element was empty
323        self.assertEqual(self.student['payments'][value].r_pay_reference, None)
324        # Here we have to stop testing because we cannot create completed bookings
325
326        # Students can download reference number slip
327        self.browser.getLink("Pay via Interswitch PAYDirect").click()
328        self.browser.getLink("Download reference number slip").click()
329        self.assertEqual(self.browser.headers['Status'], '200 Ok')
330        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
331        path = os.path.join(samples_dir(), 'refnumberslip.pdf')
332        open(path, 'wb').write(self.browser.contents)
333        print "Sample PDF refnumberslip.pdf written to %s" % path
334
335class InterswitchTestsApplicants(ApplicantsFullSetup):
336    """Tests for the Interswitch payment gateway.
337    """
338
339    layer = FunctionalLayer
340
341    def setUp(self):
342        super(InterswitchTestsApplicants, self).setUp()
343        configuration = SessionConfiguration()
344        configuration.academic_session = datetime.now().year - 2
345        self.app['configuration'].addSessionConfiguration(configuration)
346        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
347        self.browser.open(self.manage_path)
348        #IWorkflowState(self.student).setState('started')
349        super(InterswitchTestsApplicants, self).fill_correct_values()
350        self.applicantscontainer.application_fee = 1000.0
351        self.browser.getControl(name="form.nationality").value = ['NG']
352        self.browser.getControl(name="transition").value = ['start']
353        self.browser.getControl("Save").click()
354        self.browser.getControl("Add online").click()
355        self.assertMatches('...ticket created...',
356                           self.browser.contents)
357        self.payment = self.applicant.values()[0]
358        self.payment_url = self.browser.url
359
360    def test_interswitch_form(self):
361        self.assertMatches('...Amount Authorized...',
362                           self.browser.contents)
363        self.assertMatches(
364            '...<span>1000.0</span>...',
365            self.browser.contents)
366        # Manager can access InterswitchForm
367        self.browser.getLink("Pay via Interswitch CollegePAY", index=0).click()
368        self.assertMatches('...Total Amount Authorized:...',
369                           self.browser.contents)
370        self.assertMatches(
371            '...<input type="hidden" name="amount" value="100000" />...',
372            self.browser.contents)
373        delta = timedelta(days=8)
374        self.payment.creation_date -= delta
375        self.browser.open(self.payment_url)
376        self.browser.getLink("Pay via Interswitch", index=0).click()
377        self.assertMatches(
378            '...This payment ticket is too old. Please create a new ticket...',
379            self.browser.contents)
380        delta = timedelta(days=2)
381        self.payment.creation_date += delta
382        self.browser.getLink("Pay via Interswitch", index=0).click()
383        self.assertMatches('...Total Amount Authorized:...',
384                           self.browser.contents)
385
Note: See TracBrowser for help on using the repository browser.