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

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

Use IPayer adapter.

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