source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/interswitch/paydirectbrowser.py @ 16514

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

False is the default.

  • Property svn:keywords set to Id
File size: 11.8 KB
Line 
1## $Id: paydirectbrowser.py 16496 2021-05-31 13:22:19Z henrik $
2##
3## Copyright (C) 2021 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.i18n import translate
21from zope.component import getUtility
22from zope.security import checkPermission
23from xml.dom.minidom import parseString
24from waeup.kofa.interfaces import IKofaUtils
25from waeup.kofa.utils.helpers import to_timezone
26from waeup.kofa.browser.layout import UtilityView, KofaPage, KofaFormPage, action
27from waeup.kofa.browser.viewlets import ManageActionButton
28from waeup.kofa.students.interfaces import IStudentsUtils
29from waeup.kofa.students.browser import OnlinePaymentDisplayFormPage as OPDPStudent
30from waeup.kofa.students.browser import StudentBasePDFFormPage
31from waeup.kofa.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant
32from waeup.kofa.applicants.browser import ApplicantBaseDisplayFormPage
33from kofacustom.nigeria.interswitch.helpers import (
34    query_interswitch, write_payments_log,
35    fetch_booking_details, create_paydirect_booking)
36from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
37from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
38from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
39from kofacustom.nigeria.interswitch.tests import (
40    PAYDIRECT_URL, PAYDIRECT_HOST, MERCHANT_ID)
41from kofacustom.nigeria.interfaces import MessageFactory as _
42
43GATEWAY_AMT = 300.0
44
45grok.templatedir('browser_templates')
46
47def paydirect_module_activated(session, payment):
48    if payment.r_company and payment.r_company != 'interswitch':
49        return False
50    try:
51        return getattr(grok.getSite()['configuration'][str(session)],
52            'interswitch_paydirect_enabled', False)
53    except KeyError:
54        session = datetime.now().year
55        try:
56            return getattr(grok.getSite()['configuration'][str(session)],
57                'interswitch_paydirect_enabled', False)
58        except KeyError:
59            return False
60
61class PAYDirectActionButtonStudent(ManageActionButton):
62    grok.order(2)
63    grok.context(INigeriaOnlinePayment)
64    grok.view(OPDPStudent)
65    grok.require('waeup.payStudent')
66    icon = 'actionicon_pay.png'
67    text = _('Pay via Interswitch PAYDirect')
68    target = 'paydirect'
69
70    @property
71    def target_url(self):
72        if not paydirect_module_activated(
73            self.context.student.current_session, self.context):
74            return ''
75        if self.context.p_state == 'paid':
76            return ''
77        return self.view.url(self.view.context, self.target)
78
79class PAYDirectActionButtonApplicant(PAYDirectActionButtonStudent):
80    grok.view(OPDPApplicant)
81    grok.require('waeup.payApplicant')
82
83    @property
84    def target_url(self):
85        if not paydirect_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 PAYDirectPageStudent(KofaFormPage):
93    """Inform student how to proceed
94    """
95    grok.context(INigeriaStudentOnlinePayment)
96    grok.template('paydirect')
97    grok.name('paydirect')
98    grok.require('waeup.payStudent')
99    label = _('Requery Interswitch PAYDirect History')
100
101    gateway_amt = GATEWAY_AMT
102    merchant_id = MERCHANT_ID
103    gateway_url = PAYDIRECT_URL
104    gateway_host = PAYDIRECT_HOST
105    https = True
106
107    def init_update(self):
108        if self.context.p_state == 'paid':
109            return _("Payment ticket can't be used again.")
110        if self.context.r_company and self.context.r_company != 'interswitch':
111            return _("Payment ticket has been used for another payment gateway.")
112        self.ref_number = self.merchant_id + self.context.p_id[1:]
113        # Create a PAYDirect Booking
114        if not self.context.r_company:
115            result_xml = create_paydirect_booking(
116                self.merchant_id, self.context, self.gateway_host,
117                self.gateway_url, True)
118            if result_xml.startswith('Connection error'):
119                return result_xml
120            doc=parseString(result_xml)
121            if not doc.getElementsByTagName('ResponseCode'):
122                return _('Invalid callback from Interswitch')
123            rc = doc.getElementsByTagName('ResponseCode')[0].firstChild.data
124            if rc not in ('100', '108'):
125                return 'Error response code from Interswitch: %s' % rc
126        return
127
128    def update(self):
129        if not paydirect_module_activated(
130            self.context.student.current_session, self.context):
131            self.flash(_('Forbidden'), type='danger')
132            self.redirect(self.url(self.context, '@@index'))
133            return
134        error = self.init_update()
135        if error:
136            self.flash(error, type='danger')
137            self.redirect(self.url(self.context, '@@index'))
138            return
139        # Already now it becomes an Interswitch payment. We set the net amount
140        # and add the gateway amount.
141        if not self.context.r_company:
142            self.context.net_amt = self.context.amount_auth
143            self.context.amount_auth += self.gateway_amt
144            self.context.gateway_amt = self.gateway_amt
145            self.context.r_company = u'interswitch'
146        return
147
148    @action('Requery now', style='primary')
149    def fetch(self):
150        student = self.context.student
151        success, msg, log = fetch_booking_details(
152            self.context, self.merchant_id, self.gateway_host,
153            self.gateway_url, self.https)
154        student.writeLogMessage(self, log)
155        if not success:
156            self.flash(msg, type='warning')
157            self.redirect(self.url(self.context, '@@index'))
158            return
159        write_payments_log(student.student_id, self.context)
160        flashtype, msg, log = self.context.doAfterStudentPayment()
161        if log is not None:
162            student.writeLogMessage(self, log)
163        self.flash(msg, type=flashtype)
164        self.redirect(self.url(self.context, '@@index'))
165        return
166
167class PAYDirectPageApplicant(PAYDirectPageStudent):
168    """ Inform applicant how to proceed.
169    """
170    grok.context(INigeriaApplicantOnlinePayment)
171    grok.require('waeup.payApplicant')
172
173    def update(self):
174        if not paydirect_module_activated(
175            self.context.__parent__.__parent__.year, self.context):
176            self.flash(_('Forbidden'), type='danger')
177            self.redirect(self.url(self.context, '@@index'))
178            return
179        error = self.init_update()
180        if error:
181            self.flash(error, type='danger')
182            self.redirect(self.url(self.context, '@@index'))
183        if self.context.__parent__.__parent__.expired \
184            and self.context.__parent__.__parent__.strict_deadline:
185            return _("Payment ticket can't be used. "
186                     "Application period has expired.")
187        # Already now it becomes an Interswitch payment. We set the net amount
188        # and add the gateway amount.
189        if not self.context.r_company:
190            self.context.net_amt = self.context.amount_auth
191            self.context.amount_auth += self.gateway_amt
192            self.context.gateway_amt = self.gateway_amt
193            self.context.r_company = u'interswitch'
194        return
195
196    @action('Requery now', style='primary')
197    def fetch(self):
198        applicant = self.context.__parent__
199        success, msg, log = fetch_booking_details(
200            self.context, self.merchant_id, self.gateway_host,
201            self.gateway_url, self.https)
202        applicant.writeLogMessage(self, log)
203        if not success:
204            self.flash(msg, type='warning')
205            self.redirect(self.url(self.context, '@@index'))
206            return
207        write_payments_log(applicant.applicant_id, self.context)
208        flashtype, msg, log = self.context.doAfterApplicantPayment()
209        if log is not None:
210            applicant.writeLogMessage(self, log)
211        self.flash(msg, type=flashtype)
212        return
213
214class StudentPaymentRefNumberSlipActionButton(ManageActionButton):
215    grok.order(1)
216    grok.context(INigeriaStudentOnlinePayment)
217    grok.view(PAYDirectPageStudent)
218    grok.require('waeup.viewStudent')
219    icon = 'actionicon_pdf.png'
220    text = _('Download reference number slip')
221    target = 'refnumberslip.pdf'
222
223    @property
224    def target_url(self):
225        if self.context.p_state == 'paid':
226            return ''
227        return self.view.url(self.view.context, self.target)
228
229class ApplicantPaymentRefNumberSlipActionButton(StudentPaymentRefNumberSlipActionButton):
230    grok.context(INigeriaApplicantOnlinePayment)
231    grok.view(PAYDirectPageApplicant)
232    grok.require('waeup.viewApplication')
233
234class StudentRefNumberSlip(UtilityView, grok.View):
235    """Deliver a PDF slip of the context.
236    """
237    grok.context(INigeriaStudentOnlinePayment)
238    grok.name('refnumberslip.pdf')
239    grok.require('waeup.viewStudent')
240    form_fields = grok.AutoFields(INigeriaOnlinePayment).select(
241        'amount_auth', 'p_category')
242    prefix = 'form'
243    omit_fields = (
244        'password', 'suspended', 'phone', 'date_of_birth',
245        'adm_code', 'sex', 'suspended_comment', 'current_level',
246        'flash_notice', 'parents_email', 'current_mode',
247        'entry_session', 'reg_number')
248    merchant_id = MERCHANT_ID
249
250    @property
251    def refnumber(self):
252        return self.merchant_id + self.context.p_id[1:]
253
254    @property
255    def label(self):
256        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
257        return translate(_('Interswitch PAYDirect Payment'),
258            'waeup.kofa', target_language=portal_language) \
259            + ' %s' % self.refnumber
260
261    @property
262    def note(self):
263        return """<br /><br />
264Go to your bank and make your PAYDirect payment with the reference number <strong>%s</strong>.
265""" % self.refnumber
266    def render(self):
267        if self.context.p_state == 'paid':
268            self.flash('Payment has already been made.')
269            self.redirect(self.url(self.context))
270            return
271        studentview = StudentBasePDFFormPage(self.context.student,
272            self.request, self.omit_fields)
273        students_utils = getUtility(IStudentsUtils)
274        return students_utils.renderPDF(self, 'refnumberslip.pdf',
275            self.context.student, studentview, note=self.note,
276            omit_fields=self.omit_fields)
277
278class ApplicantRefNumberSlip(StudentRefNumberSlip):
279    """Deliver a PDF slip of the context.
280    """
281    grok.context(INigeriaApplicantOnlinePayment)
282    grok.require('waeup.viewApplication')
283
284    @property
285    def note(self):
286        return """<br /><br />
287Go to your bank and make your PAYDirect payment with the reference number <strong>%s</strong>.
288""" % self.refnumber
289    def render(self):
290        if self.context.p_state == 'paid':
291            self.flash('Payment has already been made.')
292            self.redirect(self.url(self.context))
293            return
294        applicantview = ApplicantBaseDisplayFormPage(self.context.__parent__,
295            self.request)
296        students_utils = getUtility(IStudentsUtils)
297        return students_utils.renderPDF(self, 'refnumberslip.pdf',
298            self.context.__parent__, applicantview, note=self.note,
299            omit_fields=self.omit_fields)
Note: See TracBrowser for help on using the repository browser.