source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/interswitch/browser.py @ 16326

Last change on this file since 16326 was 16247, checked in by Henrik Bettermann, 4 years ago

Fix typo.

  • Property svn:keywords set to Id
File size: 16.3 KB
Line 
1## $Id: browser.py 16247 2020-09-24 06:49:25Z 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##
18import grok
19from datetime import datetime, timedelta
20from zope.component import getUtility
21from zope.security import checkPermission
22from waeup.kofa.interfaces import IKofaUtils
23from waeup.kofa.utils.helpers import to_timezone
24from waeup.kofa.browser.layout import UtilityView, KofaPage
25from waeup.kofa.browser.viewlets import ManageActionButton
26from waeup.kofa.students.interfaces import IStudentsUtils
27from waeup.kofa.students.browser import OnlinePaymentDisplayFormPage as OPDPStudent
28from waeup.kofa.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant
29from kofacustom.nigeria.interswitch.helpers import (
30    query_interswitch, write_payments_log)
31from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
32from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
33from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
34from kofacustom.nigeria.interfaces import MessageFactory as _
35
36GATEWAY_AMT = 300.0
37
38# Buttons
39
40def module_activated(session, payment):
41    if payment.r_company and payment.r_company != 'interswitch':
42        return False
43    try:
44        return getattr(grok.getSite()['configuration'][str(session)],
45            'interswitch_enabled', True)
46    except KeyError:
47        session = datetime.now().year
48        try:
49            return getattr(grok.getSite()['configuration'][str(session)],
50                'interswitch_enabled', True)
51        except KeyError:
52            return False
53
54class InterswitchActionButtonStudent(ManageActionButton):
55    grok.order(1)
56    grok.context(INigeriaOnlinePayment)
57    grok.view(OPDPStudent)
58    grok.require('waeup.payStudent')
59    icon = 'actionicon_pay.png'
60    text = _('Pay via Interswitch')
61    target = 'goto_interswitch'
62
63    @property
64    def target_url(self):
65        if not module_activated(
66            self.context.student.current_session, self.context):
67            return ''
68        if self.context.p_state != 'unpaid':
69            return ''
70        return self.view.url(self.view.context, self.target)
71
72class InterswitchActionButtonApplicant(InterswitchActionButtonStudent):
73    grok.view(OPDPApplicant)
74    grok.require('waeup.payApplicant')
75
76    @property
77    def target_url(self):
78        if not module_activated(
79            self.context.__parent__.__parent__.year, self.context):
80            return ''
81        if self.context.p_state != 'unpaid':
82            return ''
83        return self.view.url(self.view.context, self.target)
84
85class InterswitchRequestWebserviceActionButtonStudent(ManageActionButton):
86    grok.order(2)
87    grok.context(INigeriaOnlinePayment)
88    grok.view(OPDPStudent)
89    grok.require('waeup.payStudent')
90    icon = 'actionicon_call.png'
91    text = _('Requery Interswitch History')
92    target = 'request_webservice'
93
94    @property
95    def target_url(self):
96        if not module_activated(
97            self.context.student.current_session, self.context):
98            return ''
99        if self.context.p_state in ('paid', 'waived', 'scholarship'):
100            return ''
101        return self.view.url(self.view.context, self.target)
102
103class InterswitchRequestWebserviceActionButtonApplicant(
104    InterswitchRequestWebserviceActionButtonStudent):
105    grok.view(OPDPApplicant)
106    grok.require('waeup.payApplicant')
107
108    @property
109    def target_url(self):
110        if not module_activated(
111            self.context.__parent__.__parent__.year, self.context):
112            return ''
113        if self.context.p_state in ('paid', 'waived', 'scholarship'):
114            return ''
115        return self.view.url(self.view.context, self.target)
116
117class InterswitchVerifyWebserviceActionButtonStudent(ManageActionButton):
118    grok.order(3)
119    grok.context(INigeriaOnlinePayment)
120    grok.view(OPDPStudent)
121    grok.require('waeup.manageStudent')
122    icon = 'actionicon_call.png'
123    text = _('Verify Payment')
124    target = 'verify_payment'
125
126    @property
127    def target_url(self):
128        if not module_activated(
129            self.context.student.current_session, self.context):
130            return ''
131        if self.context.p_state != 'paid' \
132            or self.context.r_company != u'interswitch':
133            return ''
134        return self.view.url(self.view.context, self.target)
135
136class InterswitchVerifyWebserviceActionButtonApplicant(
137    InterswitchVerifyWebserviceActionButtonStudent):
138    grok.view(OPDPApplicant)
139    grok.require('waeup.manageApplication')
140
141    @property
142    def target_url(self):
143        if not module_activated(
144            self.context.__parent__.__parent__.year, self.context):
145            return ''
146        if self.context.p_state != 'paid' \
147            or self.context.r_company != u'interswitch':
148            return ''
149        return self.view.url(self.view.context, self.target)
150
151# Webservice request views
152
153class InterswitchPaymentRequestWebservicePageStudent(UtilityView, grok.View):
154    """ Request webservice view for the CollegePAY gateway
155    """
156    grok.context(INigeriaStudentOnlinePayment)
157    grok.name('request_webservice')
158    grok.require('waeup.payStudent')
159
160    product_id = None
161    gateway_host = None
162    gateway_url = None
163    https = True
164    mac = None
165
166    def update(self):
167        if not module_activated(
168            self.context.student.current_session, self.context):
169            return
170        if self.context.p_state in ('paid', 'waived', 'scholarship'):
171            self.flash(_('This ticket has already been paid.'), type='danger')
172            return
173        student = self.context.student
174        success, msg, log = query_interswitch(
175            self.context, self.product_id,
176            self.gateway_host, self.gateway_url,
177            self.https, self.mac, False)
178        student.writeLogMessage(self, log)
179        if not success:
180            self.flash(msg, type='danger')
181            return
182        write_payments_log(student.student_id, self.context)
183        flashtype, msg, log = self.context.doAfterStudentPayment()
184        if log is not None:
185            student.writeLogMessage(self, log)
186        self.flash(msg, type=flashtype)
187        return
188
189    def render(self):
190        self.redirect(self.url(self.context, '@@index'))
191        return
192
193class InterswitchPaymentRequestWebservicePageApplicant(UtilityView, grok.View):
194    """ Request webservice view for the CollegePAY gateway
195    """
196    grok.context(INigeriaApplicantOnlinePayment)
197    grok.name('request_webservice')
198    grok.require('waeup.payApplicant')
199
200    product_id = None
201    gateway_host = None
202    gateway_url = None
203    https = True
204    mac = None
205
206    def update(self):
207        if not module_activated(
208            self.context.__parent__.__parent__.year, self.context):
209            return
210        if self.context.p_state == 'paid':
211            self.flash(_('This ticket has already been paid.'), type='danger')
212            return
213        applicant = self.context.__parent__
214        success, msg, log = query_interswitch(
215            self.context, self.product_id,
216            self.gateway_host, self.gateway_url,
217            self.https, self.mac, False)
218        applicant.writeLogMessage(self, log)
219        if not success:
220            self.flash(msg, type='danger')
221            return
222        write_payments_log(applicant.applicant_id, self.context)
223        flashtype, msg, log = self.context.doAfterApplicantPayment()
224        if log is not None:
225            applicant.writeLogMessage(self, log)
226        self.flash(msg, type=flashtype)
227        return
228
229    def render(self):
230        self.redirect(self.url(self.context.__parent__, 'edit'))
231        return
232
233class InterswitchPaymentVerifyWebservicePageStudent(UtilityView, grok.View):
234    """ Verify payment view for the CollegePAY gateway
235    """
236    grok.context(INigeriaStudentOnlinePayment)
237    grok.name('verify_payment')
238    grok.require('waeup.manageStudent')
239
240    product_id = None
241    gateway_host = None
242    gateway_url = None
243    https = True
244    mac = None
245
246    def update(self):
247        if not module_activated(
248            self.context.student.current_session, self.context):
249            return
250        if self.context.p_state  != 'paid' \
251            or self.context.r_company != u'interswitch':
252            self.flash(_('This ticket has not been paid.'), type='danger')
253            return
254        student = self.context.student
255        success, msg, log = query_interswitch(
256            self.context, self.product_id,
257            self.gateway_host, self.gateway_url,
258            self.https, self.mac, True)
259        student.writeLogMessage(self, log)
260        if not success:
261            self.flash(msg, type='danger')
262            return
263        self.flash(msg)
264        return
265
266    def render(self):
267        self.redirect(self.url(self.context, '@@index'))
268        return
269
270class InterswitchPaymentVerifyWebservicePageApplicant(UtilityView, grok.View):
271    """ Verify payment view for the CollegePAY gateway
272    """
273    grok.context(INigeriaApplicantOnlinePayment)
274    grok.name('verify_payment')
275    grok.require('waeup.manageApplication')
276
277    product_id = None
278    gateway_host = None
279    gateway_url = None
280    https = True
281    mac = None
282
283    def update(self):
284        if not module_activated(
285            self.context.__parent__.__parent__.year, self.context):
286            return
287        if self.context.p_state != 'paid' \
288            or self.context.r_company != u'interswitch':
289            self.flash(_('This ticket has not been paid.'), type='danger')
290            return
291        applicant = self.context.__parent__
292        success, msg, log = query_interswitch(
293            self.context, self.product_id,
294            self.gateway_host, self.gateway_url,
295            self.https, self.mac, True)
296        applicant.writeLogMessage(self, log)
297        if not success:
298            self.flash(msg, type='danger')
299            return
300        self.flash(msg)
301        return
302
303    def render(self):
304        self.redirect(self.url(self.context, '@@index'))
305        return
306
307# Forwarding pages
308
309class InterswitchPageStudent(KofaPage):
310    """ View which sends a POST request to the Interswitch
311    CollegePAY payment gateway.
312    """
313    grok.context(INigeriaOnlinePayment)
314    grok.name('goto_interswitch')
315    grok.template('student_goto_interswitch')
316    grok.require('waeup.payStudent')
317    label = _('Submit data to CollegePAY (Interswitch Payment Gateway)')
318    submit_button = _('Submit')
319
320    action = None
321    site_name = None
322    currency = None
323    pay_item_id = None
324    product_id = None
325    xml_data = None
326    hashvalue = None
327    gateway_amt = GATEWAY_AMT
328
329    def init_update(self):
330        if self.context.p_state == 'paid':
331            return _("Payment ticket can't be re-sent to CollegePAY.")
332        now = datetime.utcnow()
333        if self.context.creation_date.tzinfo is not None:
334            # That's bad. Please store timezone-naive datetimes only!
335            now = self.context.creation_date.tzinfo.localize(now)
336        time_delta = now - self.context.creation_date
337        if time_delta.days > 7:
338            return _("This payment ticket is too old. Please create a new ticket.")
339        if self.context.r_company and self.context.r_company != 'interswitch':
340            return _("Payment ticket has been used for another payment gateway.")
341        student = self.context.student
342        certificate = getattr(student['studycourse'],'certificate',None)
343        if certificate is None:
344            return _("Study course data are incomplete.")
345        kofa_utils = getUtility(IKofaUtils)
346        student_utils = getUtility(IStudentsUtils)
347        if student_utils.samePaymentMade(student, self.context.p_category,
348            self.context.p_item, self.context.p_session):
349            return _("This type of payment has already been made.")
350        xmldict = {}
351        if certificate is not None:
352            xmldict['department'] = certificate.__parent__.__parent__.code
353            xmldict['faculty'] = certificate.__parent__.__parent__.__parent__.code
354        else:
355            xmldict['department'] = None
356            xmldict['faculty'] = None
357        self.category = self.context.category
358        tz = kofa_utils.tzinfo
359        self.local_date_time = to_timezone(
360            self.context.creation_date, tz).strftime("%Y-%m-%d %H:%M:%S %Z")
361        self.site_redirect_url = self.url(self.context, 'request_webservice')
362        self.student = student
363        self.xmldict = xmldict
364        return
365
366    def update(self):
367        if not module_activated(
368            self.context.student.current_session, self.context):
369            self.flash(_('Forbidden'), type='danger')
370            self.redirect(self.url(self.context, '@@index'))
371            return
372        error = self.init_update()
373        if error:
374            self.flash(error, type='danger')
375            self.redirect(self.url(self.context, '@@index'))
376        # Already now it becomes an Interswitch payment. We set the net amount
377        # and add the gateway amount.
378        if not self.context.r_company:
379            self.context.net_amt = self.context.amount_auth
380            self.context.amount_auth += self.gateway_amt
381            self.context.gateway_amt = self.gateway_amt
382            self.context.r_company = u'interswitch'
383        self.amount_auth = int(100 * self.context.amount_auth)
384        return
385
386class InterswitchPageApplicant(KofaPage):
387    """ View which sends a POST request to the Interswitch
388    CollegePAY payment gateway.
389    """
390    grok.context(INigeriaApplicantOnlinePayment)
391    grok.require('waeup.payApplicant')
392    grok.template('applicant_goto_interswitch')
393    grok.name('goto_interswitch')
394    label = _('Submit data to CollegePAY (Interswitch Payment Gateway)')
395    submit_button = _('Submit')
396
397    action = None
398    site_name = None
399    currency = None
400    pay_item_id = None
401    product_id = None
402    xml_data = None
403    hashvalue = None
404    gateway_amt = GATEWAY_AMT
405
406    def init_update(self):
407        if self.context.p_state != 'unpaid':
408            return _("Payment ticket can't be re-sent to CollegePAY.")
409        if self.context.__parent__.__parent__.expired \
410            and self.context.__parent__.__parent__.strict_deadline:
411            return _("Payment ticket can't be sent to CollegePAY. "
412                     "Application period has expired.")
413        if self.context.r_company and self.context.r_company != 'interswitch':
414            return _("Payment ticket has been used for another payment gateway.")
415        tz = getUtility(IKofaUtils).tzinfo
416        time_delta = datetime.utcnow() - self.context.creation_date
417        if time_delta.days > 7:
418            return _("This payment ticket is too old. Please create a new ticket.")
419        self.applicant = self.context.__parent__
420        self.category = self.context.category
421        tz = getUtility(IKofaUtils).tzinfo
422        self.local_date_time = to_timezone(
423            self.context.creation_date, tz).strftime("%Y-%m-%d %H:%M:%S %Z")
424        self.site_redirect_url = self.url(self.context, 'request_webservice')
425        return
426
427    def update(self):
428        if not module_activated(
429            self.context.__parent__.__parent__.year, self.context):
430            self.flash(_('Forbidden'), type='danger')
431            self.redirect(self.url(self.context, '@@index'))
432            return
433        error = self.init_update()
434        if error:
435            self.flash(error, type='danger')
436            self.redirect(self.url(self.context, '@@index'))
437        # Already now it becomes an Interswitch payment. We set the net amount
438        # and add the gateway amount.
439        if not self.context.r_company:
440            self.context.net_amt = self.context.amount_auth
441            self.context.amount_auth += self.gateway_amt
442            self.context.gateway_amt = self.gateway_amt
443            self.context.r_company = u'interswitch'
444        self.amount_auth = int(100 * self.context.amount_auth)
445        return
Note: See TracBrowser for help on using the repository browser.