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

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

Do not allow to submit forms to other companies than payment.r_company.

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