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

Last change on this file since 16962 was 16587, checked in by Henrik Bettermann, 3 years ago

Set constant item_code.

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