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

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

Show correct buttons if payment state in ('paid', 'waived', 'scholarship').

  • Property svn:keywords set to Id
File size: 15.8 KB
RevLine 
[9781]1## $Id: browser.py 15842 2019-11-25 11:02:44Z 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:
47        return False
48
[9781]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'
[15702]55    text = _('Pay via Interswitch')
[9781]56    target = 'goto_interswitch'
57
58    @property
59    def target_url(self):
[15770]60        if not module_activated(
61            self.context.student.current_session, self.context):
[14755]62            return ''
[9781]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
[14755]71    @property
72    def target_url(self):
[15770]73        if not module_activated(
74            self.context.__parent__.__parent__.year, self.context):
[14755]75            return ''
76        if self.context.p_state != 'unpaid':
77            return ''
78        return self.view.url(self.view.context, self.target)
79
[9781]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'
[15702]86    text = _('Requery Interswitch History')
[9781]87    target = 'request_webservice'
88
89    @property
90    def target_url(self):
[15770]91        if not module_activated(
92            self.context.student.current_session, self.context):
[14755]93            return ''
[15842]94        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[9781]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
[14755]103    @property
104    def target_url(self):
[15770]105        if not module_activated(
106            self.context.__parent__.__parent__.year, self.context):
[14755]107            return ''
[15842]108        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[14755]109            return ''
110        return self.view.url(self.view.context, self.target)
111
[13581]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):
[15770]123        if not module_activated(
124            self.context.student.current_session, self.context):
[14755]125            return ''
[13585]126        if self.context.p_state != 'paid' \
127            or self.context.r_company != u'interswitch':
[13581]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
[14755]136    @property
137    def target_url(self):
[15770]138        if not module_activated(
139            self.context.__parent__.__parent__.year, self.context):
[14755]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)
[13581]145
146# Webservice request views
147
[9781]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
[13044]158    https = True
[13387]159    mac = None
[9781]160
161    def update(self):
[15770]162        if not module_activated(
163            self.context.student.current_session, self.context):
[14755]164            return
[15842]165        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[13579]166            self.flash(_('This ticket has already been paid.'), type='danger')
[9781]167            return
168        student = self.context.student
169        success, msg, log = query_interswitch(
[11915]170            self.context, self.product_id,
171            self.gateway_host, self.gateway_url,
[13584]172            self.https, self.mac, False)
[9781]173        student.writeLogMessage(self, log)
174        if not success:
[11579]175            self.flash(msg, type='danger')
[9781]176            return
177        write_payments_log(student.student_id, self.context)
[11581]178        flashtype, msg, log = self.context.doAfterStudentPayment()
[9781]179        if log is not None:
180            student.writeLogMessage(self, log)
[11581]181        self.flash(msg, type=flashtype)
[9781]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
[13044]198    https = True
[13387]199    mac = None
[9781]200
201    def update(self):
[15770]202        if not module_activated(
203            self.context.__parent__.__parent__.year, self.context):
[14755]204            return
[13580]205        if self.context.p_state == 'paid':
[11642]206            self.flash(_('This ticket has already been paid.'), type='danger')
[9781]207            return
208        applicant = self.context.__parent__
209        success, msg, log = query_interswitch(
[11915]210            self.context, self.product_id,
211            self.gateway_host, self.gateway_url,
[13584]212            self.https, self.mac, False)
[9781]213        applicant.writeLogMessage(self, log)
214        if not success:
[11579]215            self.flash(msg, type='danger')
[9781]216            return
217        write_payments_log(applicant.applicant_id, self.context)
[11581]218        flashtype, msg, log = self.context.doAfterApplicantPayment()
[9781]219        if log is not None:
220            applicant.writeLogMessage(self, log)
[11581]221        self.flash(msg, type=flashtype)
[9781]222        return
223
224    def render(self):
[15529]225        self.redirect(self.url(self.context.__parent__, 'edit'))
[9781]226        return
[11630]227
[13581]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):
[15770]242        if not module_activated(
243            self.context.student.current_session, self.context):
[14755]244            return
[13585]245        if self.context.p_state  != 'paid' \
246            or self.context.r_company != u'interswitch':
[13581]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,
[13584]253            self.https, self.mac, True)
[13581]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):
[15770]279        if not module_activated(
280            self.context.__parent__.__parent__.year, self.context):
[14755]281            return
[13585]282        if self.context.p_state != 'paid' \
283            or self.context.r_company != u'interswitch':
[13581]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,
[13584]290            self.https, self.mac, True)
[13581]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
[11630]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
[11639]315    action = None
316    site_name = None
317    currency = None
318    pay_item_id = None
319    product_id = None
320    xml_data = None
[12477]321    hashvalue = None
[15755]322    gateway_amt = GATEWAY_AMT
[11639]323
[11642]324    def init_update(self):
[11630]325        if self.context.p_state == 'paid':
[11642]326            return _("Payment ticket can't be re-sent to CollegePAY.")
[13478]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
[13015]332        if time_delta.days > 7:
[12973]333            return _("This payment ticket is too old. Please create a new ticket.")
[15755]334        if self.context.r_company and self.context.r_company != 'interswitch':
335            return _("Payment ticket has been used for another payment gateway.")
[11642]336        student = self.context.student
[11630]337        certificate = getattr(student['studycourse'],'certificate',None)
338        if certificate is None:
[11642]339            return _("Study course data are incomplete.")
[11639]340        kofa_utils = getUtility(IKofaUtils)
[11642]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.")
[11630]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
[12509]352        self.category = self.context.category
[11639]353        tz = kofa_utils.tzinfo
[11630]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')
[11642]357        self.student = student
358        self.xmldict = xmldict
359        return
[11630]360
[11642]361    def update(self):
[15770]362        if not module_activated(
363            self.context.student.current_session, self.context):
[14755]364            return
[11642]365        error = self.init_update()
366        if error:
367            self.flash(error, type='danger')
368            self.redirect(self.url(self.context, '@@index'))
[15755]369        # Already now it becomes an Interswitch payment. We set the net amount
370        # and add the gateway amount.
371        if not self.context.r_company:
372            self.context.net_amt = self.context.amount_auth
373            self.context.amount_auth += self.gateway_amt
374            self.context.gateway_amt = self.gateway_amt
375            self.context.r_company = u'interswitch'
376        self.amount_auth = int(100 * self.context.amount_auth)
[11642]377        return
378
[11630]379class InterswitchPageApplicant(KofaPage):
380    """ View which sends a POST request to the Interswitch
381    CollegePAY payment gateway.
382    """
383    grok.context(INigeriaApplicantOnlinePayment)
384    grok.require('waeup.payApplicant')
385    grok.template('applicant_goto_interswitch')
386    grok.name('goto_interswitch')
387    label = _('Submit data to CollegePAY (Interswitch Payment Gateway)')
388    submit_button = _('Submit')
389
[11639]390    action = None
391    site_name = None
392    currency = None
393    pay_item_id = None
394    product_id = None
395    xml_data = None
[15755]396    hashvalue = None
397    gateway_amt = GATEWAY_AMT
[11639]398
[11642]399    def init_update(self):
[11630]400        if self.context.p_state != 'unpaid':
[11642]401            return _("Payment ticket can't be re-sent to CollegePAY.")
[11630]402        if self.context.__parent__.__parent__.expired \
403            and self.context.__parent__.__parent__.strict_deadline:
[11642]404            return _("Payment ticket can't be send to CollegePAY. "
405                     "Application period has expired.")
[15755]406        if self.context.r_company and self.context.r_company != 'interswitch':
407            return _("Payment ticket has been used for another payment gateway.")
[12973]408        tz = getUtility(IKofaUtils).tzinfo
409        time_delta = datetime.utcnow() - self.context.creation_date
[13015]410        if time_delta.days > 7:
[12973]411            return _("This payment ticket is too old. Please create a new ticket.")
[11630]412        self.applicant = self.context.__parent__
[12509]413        self.category = self.context.category
[11630]414        tz = getUtility(IKofaUtils).tzinfo
415        self.local_date_time = to_timezone(
416            self.context.creation_date, tz).strftime("%Y-%m-%d %H:%M:%S %Z")
417        self.site_redirect_url = self.url(self.context, 'request_webservice')
[11642]418        return
419
420    def update(self):
[15770]421        if not module_activated(
422            self.context.__parent__.__parent__.year, self.context):
[14755]423            return
[11642]424        error = self.init_update()
425        if error:
426            self.flash(error, type='danger')
427            self.redirect(self.url(self.context, '@@index'))
[15755]428        # Already now it becomes an Interswitch payment. We set the net amount
429        # and add the gateway amount.
430        if not self.context.r_company:
431            self.context.net_amt = self.context.amount_auth
432            self.context.amount_auth += self.gateway_amt
433            self.context.gateway_amt = self.gateway_amt
434            self.context.r_company = u'interswitch'
435        self.amount_auth = int(100 * self.context.amount_auth)
[13478]436        return
Note: See TracBrowser for help on using the repository browser.