source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/etranzact/credobrowser.py @ 17754

Last change on this file since 17754 was 17730, checked in by Henrik Bettermann, 8 months ago

Implement Etranzact Credo platform payments.

  • Property svn:executable set to *
File size: 10.9 KB
RevLine 
[17730]1## $Id: studentsbrowser.py 15599 2019-09-20 13:24:59Z henrik $
2##
3## Copyright (C) 2017 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
19import hashlib
20from datetime import datetime, timedelta
21from zope.component import getUtility
22from zope.security import checkPermission
23from waeup.kofa.interfaces import IKofaUtils
24from waeup.kofa.utils.helpers import to_timezone
25from waeup.kofa.browser.layout import UtilityView, KofaPage, KofaEditFormPage, action, NullValidator
26from waeup.kofa.browser.viewlets import ManageActionButton
27from kofacustom.nigeria.etranzact.helpers import (
28    write_payments_log,
29    initiate_payment,
30    query_credo_payment)
31from kofacustom.nigeria.students.browser import NigeriaOnlinePaymentDisplayFormPage as NOPDPStudent
32from kofacustom.nigeria.applicants.browser import NigeriaOnlinePaymentDisplayFormPage as NOPDPApplicant
33from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
34from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
35from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
36from kofacustom.nigeria.interfaces import MessageFactory as _
37
38from kofacustom.nigeria.etranzact.tests import (
39    TERMINAL_ID, CREDO_HOST, HTTPS, SECRET_API_KEY, API_PUBLIC_KEY,
40    LOGO_URL, GATEWAY_AMT)
41
42grok.templatedir('browser_templates')
43
44def credo_module_activated(session, payment):
45    if payment.p_currency != 'NGN':
46        return False
47    if payment.r_company and payment.r_company != 'etranzact':
48        return False
49    try:
50        return getattr(grok.getSite()['configuration'][str(session)],
51            'etranzact_credo_enabled', False)
52    except KeyError:
53        session = datetime.now().year
54        try:
55            return getattr(grok.getSite()['configuration'][str(session)],
56                'etranzact_credo_enabled', False)
57        except KeyError:
58            return False
59
60class CredoActionButtonStudent(ManageActionButton):
61    grok.order(8)
62    grok.context(INigeriaOnlinePayment)
63    grok.view(NOPDPStudent)
64    grok.require('waeup.payStudent')
65    icon = 'actionicon_pay.png'
66    text = _('Pay via Etranzact Credo')
67    target = 'goto_credo'
68
69    @property
70    def target_url(self):
71        if not credo_module_activated(
72            self.context.student.current_session, self.context):
73            return ''
74        if self.context.p_state != 'unpaid':
75            return ''
76        return self.view.url(self.view.context, self.target)
77
78class CredoActionButtonApplicant(CredoActionButtonStudent):
79    grok.context(INigeriaOnlinePayment)
80    grok.require('waeup.payApplicant')
81    grok.view(NOPDPApplicant)
82
83    @property
84    def target_url(self):
85        if not credo_module_activated(
86            self.context.__parent__.__parent__.year, self.context):
87            return ''
88        if self.context.p_state != 'unpaid':
89            return ''
90        return self.view.url(self.view.context, self.target)
91
92class CredoVerifyActionButtonStudent(ManageActionButton):
93    grok.order(9)
94    grok.context(INigeriaOnlinePayment)
95    grok.view(NOPDPStudent)
96    grok.require('waeup.payStudent')
97    icon = 'actionicon_call.png'
98    text = _('Requery Etranzact Credo')
99    target = 'requery_credo'
100
101    @property
102    def target_url(self):
103        if not credo_module_activated(
104            self.context.student.current_session, self.context):
105            return ''
106        if self.context.p_state in ('paid', 'waived', 'scholarship', 'failed'):
107            return ''
108        return self.view.url(self.view.context, self.target)
109
110class CredoVerifyActionButtonApplicant(CredoVerifyActionButtonStudent):
111    grok.view(NOPDPApplicant)
112    grok.require('waeup.payApplicant')
113    icon = 'actionicon_call.png'
114    text = _('Requery Etranzact Credo')
115    target = 'requery_credo'
116
117    @property
118    def target_url(self):
119        if not credo_module_activated(
120            self.context.__parent__.__parent__.year, self.context):
121            return ''
122        if self.context.p_state in ('paid', 'waived', 'scholarship', 'failed'):
123            return ''
124        return self.view.url(self.view.context, self.target)
125
126class CredoPageStudent(KofaEditFormPage):
127    """ View which sends a POST request to the Credo payment gateway.
128    """
129    grok.context(INigeriaStudentOnlinePayment)
130    grok.name('goto_credo')
131    grok.template('goto_credo')
132    grok.require('waeup.payStudent')
133    label = _('Pay via Credo')
134    submit_button = _('Pay now')
135
136    host = CREDO_HOST
137    api_public_key = API_PUBLIC_KEY
138    gateway_amt = 0.0 # is being added by Etranzact
139
140    def init_update(self):
141        if self.context.p_state == 'paid':
142            return _("Payment ticket can't be re-sent to Etranzact.")
143        now = datetime.utcnow()
144        if self.context.creation_date.tzinfo is not None:
145            # That's bad. Please store timezone-naive datetimes only!
146            now = self.context.creation_date.tzinfo.localize(now)
147        time_delta = now - self.context.creation_date
148        if time_delta.days > 7:
149            return _("This payment ticket is too old. Please create a new ticket.")
150        self.callbackUrl = self.url(self.context, 'requery_credo')
151        return
152
153    def update(self):
154        if not credo_module_activated(
155            self.context.student.current_session, self.context):
156            self.flash(_('Forbidden'), type='danger')
157            self.redirect(self.url(self.context, '@@index'))
158            return
159        # Already now it becomes an Etranzact payment. We set the net amount
160        # and add the gateway amount.
161        if not self.context.r_company:
162            self.context.net_amt = self.context.amount_auth
163            #self.context.amount_auth += self.gateway_amt
164            #self.context.gateway_amt = self.gateway_amt
165            self.context.r_company = u'etranzact'
166        #self.amount = "%.1f" % (100.0 * self.context.amount_auth)
167        error = self.init_update()
168        self.customer = self.context.student
169        if error:
170            self.flash(error, type='danger')
171            self.redirect(self.url(self.context, '@@index'))
172            return
173        return
174
175    @action(_('Pay now'), validator=NullValidator, style='primary')
176    def pay(self, **data):
177        success, url_or_message = initiate_payment(
178            self.context, self.host, self.callbackUrl, self.api_public_key)
179        if success:
180            self.redirect(url_or_message, trusted=True)
181        else:
182            self.flash(url_or_message, type='danger')
183            self.redirect(self.url(self.context, '@@index'))
184        return
185
186class CredoPageApplicant(CredoPageStudent):
187    """ View which sends a POST request to the Credo payment gateway.
188    """
189    grok.require('waeup.payApplicant')
190    grok.context(INigeriaApplicantOnlinePayment)
191
192    def update(self):
193        if not credo_module_activated(
194            self.context.__parent__.__parent__.year, self.context):
195            self.flash(_('Forbidden'), type='danger')
196            self.redirect(self.url(self.context, '@@index'))
197            return
198        # Already now it becomes an Etranzact payment. We set the net amount
199        # and add the gateway amount.
200        if not self.context.r_company:
201            self.context.net_amt = self.context.amount_auth
202            #self.context.amount_auth += self.gateway_amt
203            #self.context.gateway_amt = self.gateway_amt
204            self.context.r_company = u'etranzact'
205        #self.amount = "%.1f" % (100.0 * self.context.amount_auth)
206        error = self.init_update()
207        self.customer = self.context.__parent__
208        if error:
209            self.flash(error, type='danger')
210            self.redirect(self.url(self.context, '@@index'))
211            return
212        return
213
214class CredoVerifyPaymentStatusPageStudent(UtilityView, grok.View):
215    """ Request webservice view for the Etranzact Credo gateway.
216    """
217    grok.context(INigeriaStudentOnlinePayment)
218    grok.name('requery_credo')
219    grok.require('waeup.payStudent')
220
221    host = CREDO_HOST
222    secret_api_key = SECRET_API_KEY
223
224    def update(self):
225        if not credo_module_activated(
226            self.context.student.current_session, self.context):
227            self.flash(_('Forbidden'), type='danger')
228            self.redirect(self.url(self.context, '@@index'))
229            return
230        if self.context.p_state in ('paid', 'waived', 'scholarship', 'failed'):
231            self.flash(_('This ticket has already been processed.'), type='danger')
232            return
233        student = self.context.student
234        #verify = False
235        success, msg, log = query_credo_payment(self.context, self.host, self.secret_api_key)
236        student.writeLogMessage(self, log)
237        if not success:
238            self.flash(msg, type='danger')
239            return
240        write_payments_log(student.student_id, self.context)
241        flashtype, msg, log = self.context.doAfterStudentPayment()
242        if log is not None:
243            student.writeLogMessage(self, log)
244        self.flash(msg, type=flashtype)
245        return
246
247    def render(self):
248        self.redirect(self.url(self.context))
249        return
250
251
252class CredoVerifyPaymentStatusPageApplicant(CredoVerifyPaymentStatusPageStudent):
253    """ Request webservice view for the Etranzact Credo gateway.
254    """
255    grok.context(INigeriaApplicantOnlinePayment)
256    grok.name('requery_credo')
257    grok.require('waeup.payApplicant')
258
259    def update(self):
260        if not credo_module_activated(
261            self.context.__parent__.__parent__.year, self.context):
262            self.flash(_('Forbidden'), type='danger')
263            self.redirect(self.url(self.context, '@@index'))
264            return
265        if self.context.p_state in ('paid', 'waived', 'scholarship', 'failed'):
266            self.flash(_('This ticket has already been processed.'), type='danger')
267            return
268        applicant = self.context.__parent__
269        #verify = False
270        success, msg, log = query_credo_payment(self.context, self.host, self.secret_api_key)
271        applicant.writeLogMessage(self, log)
272        if not success:
273            self.flash(msg, type='danger')
274            return
275        write_payments_log(applicant.applicant_id, self.context)
276        flashtype, msg, log = self.context.doAfterApplicantPayment()
277        if log is not None:
278            applicant.writeLogMessage(self, log)
279        self.flash(msg, type=flashtype)
280        return
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
Note: See TracBrowser for help on using the repository browser.