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

Last change on this file since 14735 was 13585, checked in by Henrik Bettermann, 10 years ago

Only Interswitch payments are suitable for verification.

Do no change payment ticket if response code is 20050.

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