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

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

Fix typo.

  • Property svn:keywords set to Id
File size: 16.3 KB
RevLine 
[9781]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
[12973]19from datetime import datetime, timedelta
[11630]20from zope.component import getUtility
[13578]21from zope.security import checkPermission
[11630]22from waeup.kofa.interfaces import IKofaUtils
23from waeup.kofa.utils.helpers import to_timezone
24from waeup.kofa.browser.layout import UtilityView, KofaPage
[9781]25from waeup.kofa.browser.viewlets import ManageActionButton
[11642]26from waeup.kofa.students.interfaces import IStudentsUtils
[9781]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
[15755]36GATEWAY_AMT = 300.0
37
[13581]38# Buttons
39
[15770]40def module_activated(session, payment):
41    if payment.r_company and payment.r_company != 'interswitch':
42        return False
[14755]43    try:
44        return getattr(grok.getSite()['configuration'][str(session)],
45            'interswitch_enabled', True)
46    except KeyError:
[16246]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
[14755]53
[9781]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'
[15702]60    text = _('Pay via Interswitch')
[9781]61    target = 'goto_interswitch'
62
63    @property
64    def target_url(self):
[15770]65        if not module_activated(
66            self.context.student.current_session, self.context):
[14755]67            return ''
[9781]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
[14755]76    @property
77    def target_url(self):
[15770]78        if not module_activated(
79            self.context.__parent__.__parent__.year, self.context):
[14755]80            return ''
81        if self.context.p_state != 'unpaid':
82            return ''
83        return self.view.url(self.view.context, self.target)
84
[9781]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'
[15702]91    text = _('Requery Interswitch History')
[9781]92    target = 'request_webservice'
93
94    @property
95    def target_url(self):
[15770]96        if not module_activated(
97            self.context.student.current_session, self.context):
[14755]98            return ''
[15842]99        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[9781]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
[14755]108    @property
109    def target_url(self):
[15770]110        if not module_activated(
111            self.context.__parent__.__parent__.year, self.context):
[14755]112            return ''
[15842]113        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[14755]114            return ''
115        return self.view.url(self.view.context, self.target)
116
[13581]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):
[15770]128        if not module_activated(
129            self.context.student.current_session, self.context):
[14755]130            return ''
[13585]131        if self.context.p_state != 'paid' \
132            or self.context.r_company != u'interswitch':
[13581]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
[14755]141    @property
142    def target_url(self):
[15770]143        if not module_activated(
144            self.context.__parent__.__parent__.year, self.context):
[14755]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)
[13581]150
151# Webservice request views
152
[9781]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
[13044]163    https = True
[13387]164    mac = None
[9781]165
166    def update(self):
[15770]167        if not module_activated(
168            self.context.student.current_session, self.context):
[14755]169            return
[15842]170        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[13579]171            self.flash(_('This ticket has already been paid.'), type='danger')
[9781]172            return
173        student = self.context.student
174        success, msg, log = query_interswitch(
[11915]175            self.context, self.product_id,
176            self.gateway_host, self.gateway_url,
[13584]177            self.https, self.mac, False)
[9781]178        student.writeLogMessage(self, log)
179        if not success:
[11579]180            self.flash(msg, type='danger')
[9781]181            return
182        write_payments_log(student.student_id, self.context)
[11581]183        flashtype, msg, log = self.context.doAfterStudentPayment()
[9781]184        if log is not None:
185            student.writeLogMessage(self, log)
[11581]186        self.flash(msg, type=flashtype)
[9781]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
[13044]203    https = True
[13387]204    mac = None
[9781]205
206    def update(self):
[15770]207        if not module_activated(
208            self.context.__parent__.__parent__.year, self.context):
[14755]209            return
[13580]210        if self.context.p_state == 'paid':
[11642]211            self.flash(_('This ticket has already been paid.'), type='danger')
[9781]212            return
213        applicant = self.context.__parent__
214        success, msg, log = query_interswitch(
[11915]215            self.context, self.product_id,
216            self.gateway_host, self.gateway_url,
[13584]217            self.https, self.mac, False)
[9781]218        applicant.writeLogMessage(self, log)
219        if not success:
[11579]220            self.flash(msg, type='danger')
[9781]221            return
222        write_payments_log(applicant.applicant_id, self.context)
[11581]223        flashtype, msg, log = self.context.doAfterApplicantPayment()
[9781]224        if log is not None:
225            applicant.writeLogMessage(self, log)
[11581]226        self.flash(msg, type=flashtype)
[9781]227        return
228
229    def render(self):
[15529]230        self.redirect(self.url(self.context.__parent__, 'edit'))
[9781]231        return
[11630]232
[13581]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):
[15770]247        if not module_activated(
248            self.context.student.current_session, self.context):
[14755]249            return
[13585]250        if self.context.p_state  != 'paid' \
251            or self.context.r_company != u'interswitch':
[13581]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,
[13584]258            self.https, self.mac, True)
[13581]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):
[15770]284        if not module_activated(
285            self.context.__parent__.__parent__.year, self.context):
[14755]286            return
[13585]287        if self.context.p_state != 'paid' \
288            or self.context.r_company != u'interswitch':
[13581]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,
[13584]295            self.https, self.mac, True)
[13581]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
[11630]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
[11639]320    action = None
321    site_name = None
322    currency = None
323    pay_item_id = None
324    product_id = None
325    xml_data = None
[12477]326    hashvalue = None
[15755]327    gateway_amt = GATEWAY_AMT
[11639]328
[11642]329    def init_update(self):
[11630]330        if self.context.p_state == 'paid':
[11642]331            return _("Payment ticket can't be re-sent to CollegePAY.")
[13478]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
[13015]337        if time_delta.days > 7:
[12973]338            return _("This payment ticket is too old. Please create a new ticket.")
[15755]339        if self.context.r_company and self.context.r_company != 'interswitch':
340            return _("Payment ticket has been used for another payment gateway.")
[11642]341        student = self.context.student
[11630]342        certificate = getattr(student['studycourse'],'certificate',None)
343        if certificate is None:
[11642]344            return _("Study course data are incomplete.")
[11639]345        kofa_utils = getUtility(IKofaUtils)
[11642]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.")
[11630]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
[12509]357        self.category = self.context.category
[11639]358        tz = kofa_utils.tzinfo
[11630]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')
[11642]362        self.student = student
363        self.xmldict = xmldict
364        return
[11630]365
[11642]366    def update(self):
[15770]367        if not module_activated(
368            self.context.student.current_session, self.context):
[15974]369            self.flash(_('Forbidden'), type='danger')
370            self.redirect(self.url(self.context, '@@index'))
[14755]371            return
[11642]372        error = self.init_update()
373        if error:
374            self.flash(error, type='danger')
375            self.redirect(self.url(self.context, '@@index'))
[15755]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)
[11642]384        return
385
[11630]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
[11639]397    action = None
398    site_name = None
399    currency = None
400    pay_item_id = None
401    product_id = None
402    xml_data = None
[15755]403    hashvalue = None
404    gateway_amt = GATEWAY_AMT
[11639]405
[11642]406    def init_update(self):
[11630]407        if self.context.p_state != 'unpaid':
[11642]408            return _("Payment ticket can't be re-sent to CollegePAY.")
[11630]409        if self.context.__parent__.__parent__.expired \
410            and self.context.__parent__.__parent__.strict_deadline:
[16247]411            return _("Payment ticket can't be sent to CollegePAY. "
[11642]412                     "Application period has expired.")
[15755]413        if self.context.r_company and self.context.r_company != 'interswitch':
414            return _("Payment ticket has been used for another payment gateway.")
[12973]415        tz = getUtility(IKofaUtils).tzinfo
416        time_delta = datetime.utcnow() - self.context.creation_date
[13015]417        if time_delta.days > 7:
[12973]418            return _("This payment ticket is too old. Please create a new ticket.")
[11630]419        self.applicant = self.context.__parent__
[12509]420        self.category = self.context.category
[11630]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')
[11642]425        return
426
427    def update(self):
[15770]428        if not module_activated(
429            self.context.__parent__.__parent__.year, self.context):
[15974]430            self.flash(_('Forbidden'), type='danger')
431            self.redirect(self.url(self.context, '@@index'))
[14755]432            return
[11642]433        error = self.init_update()
434        if error:
435            self.flash(error, type='danger')
436            self.redirect(self.url(self.context, '@@index'))
[15755]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)
[13478]445        return
Note: See TracBrowser for help on using the repository browser.