source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/payoutletbrowser.py @ 15702

Last change on this file since 15702 was 15702, checked in by Henrik Bettermann, 5 years ago

Add first Payoutlet components. Not yet tested.
Rename eTranzact.

File size: 9.0 KB
Line 
1## $Id: browser.py 15346 2019-03-06 22:19:56Z henrik $
2##
3## Copyright (C) 2012 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##
18from datetime import datetime
19import httplib
20import urllib
21import urllib2
22import re
23from xml.dom.minidom import parseString
24import grok
25from zope.component import getUtility
26from zope.catalog.interfaces import ICatalog
27from waeup.kofa.interfaces import IUniversity, CLEARED
28from waeup.kofa.payments.interfaces import IPayer
29from waeup.kofa.webservices import PaymentDataWebservice
30from waeup.kofa.browser.layout import KofaPage, UtilityView
31from waeup.kofa.students.viewlets import ApprovePaymentActionButton as APABStudent
32from waeup.kofa.applicants.viewlets import ApprovePaymentActionButton as APABApplicant
33from kofacustom.nigeria.interswitch.browser import (
34    InterswitchActionButtonStudent,
35    InterswitchRequestWebserviceActionButtonStudent,
36    InterswitchActionButtonApplicant,
37    InterswitchRequestWebserviceActionButtonApplicant)
38from kofacustom.nigeria.interfaces import MessageFactory as _
39from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
40from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
41from kofacustom.nigeria.etranzact.tests import PAYOUTLET_QUERY_URL, TERMINAL_ID
42
43grok.templatedir('browser_templates')
44
45def module_activated(session):
46    try:
47        return getattr(grok.getSite()['configuration'][str(session)],
48            'etranzact_payoutlet_enabled', False)
49    except KeyError:
50        return False
51
52# Requerying Etranzact Payoutlet payments
53
54def 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
115
116class EtranzactEnterPinActionButtonApplicant(APABApplicant):
117    grok.context(INigeriaApplicantOnlinePayment)
118    grok.require('waeup.payApplicant')
119    grok.order(3)
120    icon = 'actionicon_call.png'
121    text = _('Enter Etranzact PIN')
122    target = 'enterpin'
123
124    @property
125    def target_url(self):
126        if not module_activated(self.context.__parent__.__parent__.year):
127            return ''
128        if self.context.p_state != 'unpaid':
129            return ''
130        return self.view.url(self.view.context, self.target)
131
132class EtranzactEnterPinActionButtonStudent(APABStudent):
133    grok.context(INigeriaStudentOnlinePayment)
134    grok.require('waeup.payStudent')
135    grok.order(3)
136    icon = 'actionicon_call.png'
137    text = _('Enter Etranzact PIN')
138    target = 'enterpin'
139
140    @property
141    def target_url(self):
142        if not module_activated(self.context.student.current_session):
143            return ''
144        if self.context.p_state != 'unpaid':
145            return ''
146        return self.view.url(self.view.context, self.target)
147
148class EtranzactEnterPinPageStudent(KofaPage):
149    """
150    """
151    grok.context(INigeriaStudentOnlinePayment)
152    grok.name('enterpin')
153    grok.template('enterpin')
154    grok.require('waeup.payStudent')
155
156    buttonname = _('Submit to Etranzact')
157    label = _('Requery Etranzact History')
158    action = 'query_payoutlet_history'
159    placeholder = _('Confirmation Number (PIN)')
160
161    def update(self):
162        if not module_activated(self.context.student.current_session):
163            return
164        super(EtranzactEnterPinPageStudent, self).update()
165        return
166
167class EtranzactEnterPinPageApplicant(EtranzactEnterPinPageStudent):
168    """
169    """
170    grok.require('waeup.payApplicant')
171    grok.context(INigeriaApplicantOnlinePayment)
172
173class EtranzactQueryHistoryPageStudent(UtilityView, grok.View):
174    """ Query history of Etranzact payments
175    """
176    grok.context(INigeriaStudentOnlinePayment)
177    grok.name('query_payoutlet_history')
178    grok.require('waeup.payStudent')
179    terminal_id = TERMINAL_ID
180    query_url = PAYOUTLET_QUERY_URL
181
182    def update(self, confirmation_number=None):
183        if not module_activated(self.context.student.current_session):
184            return
185        if self.context.p_state == 'paid':
186            self.flash(_('This ticket has already been paid.'))
187            return
188        student = self.context.student
189        success, msg, log = query_payoutlet(
190            confirmation_number,self.context, self.terminal_id, self.query_url)
191        student.writeLogMessage(self, log)
192        if not success:
193            self.flash(msg)
194            return
195        flashtype, msg, log = self.context.doAfterStudentPayment()
196        if log is not None:
197            student.writeLogMessage(self, log)
198        self.flash(msg, type=flashtype)
199        return
200
201    def render(self):
202        self.redirect(self.url(self.context, '@@index'))
203        return
204
205class EtranzactQueryHistoryPageApplicant(UtilityView, grok.View):
206    """ Query history of Etranzact payments
207    """
208    grok.context(INigeriaApplicantOnlinePayment)
209    grok.name('query_payoutlet_history')
210    grok.require('waeup.payApplicant')
211    terminal_id = TERMINAL_ID
212    query_url = PAYOUTLET_QUERY_URL
213
214    def update(self, confirmation_number=None):
215        if not module_activated(self.context.__parent__.__parent__.year):
216            return
217        ob_class = self.__implemented__.__name__
218        if self.context.p_state == 'paid':
219            self.flash(_('This ticket has already been paid.'))
220            return
221        applicant = self.context.__parent__
222        success, msg, log = query_payoutlet(
223            confirmation_number,self.context, self.terminal_id, self.query_url)
224        applicant.writeLogMessage(self, log)
225        if not success:
226            self.flash(msg)
227            return
228        flashtype, msg, log = self.context.doAfterApplicantPayment()
229        if log is not None:
230            applicant.writeLogMessage(self, log)
231        self.flash(msg, type=flashtype)
232        return
233
234    def render(self):
235        self.redirect(self.url(self.context, '@@index'))
236        return
Note: See TracBrowser for help on using the repository browser.