## $Id: paydirectbrowser.py 16496 2021-05-31 13:22:19Z henrik $ ## ## Copyright (C) 2021 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## import grok from datetime import datetime, timedelta from zope.i18n import translate from zope.component import getUtility from zope.security import checkPermission from xml.dom.minidom import parseString from waeup.kofa.interfaces import IKofaUtils from waeup.kofa.utils.helpers import to_timezone from waeup.kofa.browser.layout import UtilityView, KofaPage, KofaFormPage, action from waeup.kofa.browser.viewlets import ManageActionButton from waeup.kofa.students.interfaces import IStudentsUtils from waeup.kofa.students.browser import OnlinePaymentDisplayFormPage as OPDPStudent from waeup.kofa.students.browser import StudentBasePDFFormPage from waeup.kofa.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant from waeup.kofa.applicants.browser import ApplicantBaseDisplayFormPage from kofacustom.nigeria.interswitch.helpers import ( query_interswitch, write_payments_log, fetch_booking_details, create_paydirect_booking) from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment from kofacustom.nigeria.interswitch.tests import ( PAYDIRECT_URL, PAYDIRECT_HOST, MERCHANT_ID) from kofacustom.nigeria.interfaces import MessageFactory as _ GATEWAY_AMT = 300.0 grok.templatedir('browser_templates') def paydirect_module_activated(session, payment): if payment.r_company and payment.r_company != 'interswitch': return False try: return getattr(grok.getSite()['configuration'][str(session)], 'interswitch_paydirect_enabled', False) except KeyError: session = datetime.now().year try: return getattr(grok.getSite()['configuration'][str(session)], 'interswitch_paydirect_enabled', False) except KeyError: return False class PAYDirectActionButtonStudent(ManageActionButton): grok.order(2) grok.context(INigeriaOnlinePayment) grok.view(OPDPStudent) grok.require('waeup.payStudent') icon = 'actionicon_pay.png' text = _('Pay via Interswitch PAYDirect') target = 'paydirect' @property def target_url(self): if not paydirect_module_activated( self.context.student.current_session, self.context): return '' if self.context.p_state == 'paid': return '' return self.view.url(self.view.context, self.target) class PAYDirectActionButtonApplicant(PAYDirectActionButtonStudent): grok.view(OPDPApplicant) grok.require('waeup.payApplicant') @property def target_url(self): if not paydirect_module_activated( self.context.__parent__.__parent__.year, self.context): return '' if self.context.p_state != 'unpaid': return '' return self.view.url(self.view.context, self.target) class PAYDirectPageStudent(KofaFormPage): """Inform student how to proceed """ grok.context(INigeriaStudentOnlinePayment) grok.template('paydirect') grok.name('paydirect') grok.require('waeup.payStudent') label = _('Requery Interswitch PAYDirect History') gateway_amt = GATEWAY_AMT merchant_id = MERCHANT_ID gateway_url = PAYDIRECT_URL gateway_host = PAYDIRECT_HOST https = True def init_update(self): if self.context.p_state == 'paid': return _("Payment ticket can't be used again.") if self.context.r_company and self.context.r_company != 'interswitch': return _("Payment ticket has been used for another payment gateway.") self.ref_number = self.merchant_id + self.context.p_id[1:] # Create a PAYDirect Booking if not self.context.r_company: result_xml = create_paydirect_booking( self.merchant_id, self.context, self.gateway_host, self.gateway_url, True) if result_xml.startswith('Connection error'): return result_xml doc=parseString(result_xml) if not doc.getElementsByTagName('ResponseCode'): return _('Invalid callback from Interswitch') rc = doc.getElementsByTagName('ResponseCode')[0].firstChild.data if rc not in ('100', '108'): return 'Error response code from Interswitch: %s' % rc return def update(self): if not paydirect_module_activated( self.context.student.current_session, self.context): self.flash(_('Forbidden'), type='danger') self.redirect(self.url(self.context, '@@index')) return error = self.init_update() if error: self.flash(error, type='danger') self.redirect(self.url(self.context, '@@index')) return # Already now it becomes an Interswitch payment. We set the net amount # and add the gateway amount. if not self.context.r_company: self.context.net_amt = self.context.amount_auth self.context.amount_auth += self.gateway_amt self.context.gateway_amt = self.gateway_amt self.context.r_company = u'interswitch' return @action('Requery now', style='primary') def fetch(self): student = self.context.student success, msg, log = fetch_booking_details( self.context, self.merchant_id, self.gateway_host, self.gateway_url, self.https) student.writeLogMessage(self, log) if not success: self.flash(msg, type='warning') self.redirect(self.url(self.context, '@@index')) return write_payments_log(student.student_id, self.context) flashtype, msg, log = self.context.doAfterStudentPayment() if log is not None: student.writeLogMessage(self, log) self.flash(msg, type=flashtype) self.redirect(self.url(self.context, '@@index')) return class PAYDirectPageApplicant(PAYDirectPageStudent): """ Inform applicant how to proceed. """ grok.context(INigeriaApplicantOnlinePayment) grok.require('waeup.payApplicant') def update(self): if not paydirect_module_activated( self.context.__parent__.__parent__.year, self.context): self.flash(_('Forbidden'), type='danger') self.redirect(self.url(self.context, '@@index')) return error = self.init_update() if error: self.flash(error, type='danger') self.redirect(self.url(self.context, '@@index')) if self.context.__parent__.__parent__.expired \ and self.context.__parent__.__parent__.strict_deadline: return _("Payment ticket can't be used. " "Application period has expired.") # Already now it becomes an Interswitch payment. We set the net amount # and add the gateway amount. if not self.context.r_company: self.context.net_amt = self.context.amount_auth self.context.amount_auth += self.gateway_amt self.context.gateway_amt = self.gateway_amt self.context.r_company = u'interswitch' return @action('Requery now', style='primary') def fetch(self): applicant = self.context.__parent__ success, msg, log = fetch_booking_details( self.context, self.merchant_id, self.gateway_host, self.gateway_url, self.https) applicant.writeLogMessage(self, log) if not success: self.flash(msg, type='warning') self.redirect(self.url(self.context, '@@index')) return write_payments_log(applicant.applicant_id, self.context) flashtype, msg, log = self.context.doAfterApplicantPayment() if log is not None: applicant.writeLogMessage(self, log) self.flash(msg, type=flashtype) return class StudentPaymentRefNumberSlipActionButton(ManageActionButton): grok.order(1) grok.context(INigeriaStudentOnlinePayment) grok.view(PAYDirectPageStudent) grok.require('waeup.viewStudent') icon = 'actionicon_pdf.png' text = _('Download reference number slip') target = 'refnumberslip.pdf' @property def target_url(self): if self.context.p_state == 'paid': return '' return self.view.url(self.view.context, self.target) class ApplicantPaymentRefNumberSlipActionButton(StudentPaymentRefNumberSlipActionButton): grok.context(INigeriaApplicantOnlinePayment) grok.view(PAYDirectPageApplicant) grok.require('waeup.viewApplication') class StudentRefNumberSlip(UtilityView, grok.View): """Deliver a PDF slip of the context. """ grok.context(INigeriaStudentOnlinePayment) grok.name('refnumberslip.pdf') grok.require('waeup.viewStudent') form_fields = grok.AutoFields(INigeriaOnlinePayment).select( 'amount_auth', 'p_category') prefix = 'form' omit_fields = ( 'password', 'suspended', 'phone', 'date_of_birth', 'adm_code', 'sex', 'suspended_comment', 'current_level', 'flash_notice', 'parents_email', 'current_mode', 'entry_session', 'reg_number') merchant_id = MERCHANT_ID @property def refnumber(self): return self.merchant_id + self.context.p_id[1:] @property def label(self): portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE return translate(_('Interswitch PAYDirect Payment'), 'waeup.kofa', target_language=portal_language) \ + ' %s' % self.refnumber @property def note(self): return """

Go to your bank and make your PAYDirect payment with the reference number %s. """ % self.refnumber def render(self): if self.context.p_state == 'paid': self.flash('Payment has already been made.') self.redirect(self.url(self.context)) return studentview = StudentBasePDFFormPage(self.context.student, self.request, self.omit_fields) students_utils = getUtility(IStudentsUtils) return students_utils.renderPDF(self, 'refnumberslip.pdf', self.context.student, studentview, note=self.note, omit_fields=self.omit_fields) class ApplicantRefNumberSlip(StudentRefNumberSlip): """Deliver a PDF slip of the context. """ grok.context(INigeriaApplicantOnlinePayment) grok.require('waeup.viewApplication') @property def note(self): return """

Go to your bank and make your PAYDirect payment with the reference number %s. """ % self.refnumber def render(self): if self.context.p_state == 'paid': self.flash('Payment has already been made.') self.redirect(self.url(self.context)) return applicantview = ApplicantBaseDisplayFormPage(self.context.__parent__, self.request) students_utils = getUtility(IStudentsUtils) return students_utils.renderPDF(self, 'refnumberslip.pdf', self.context.__parent__, applicantview, note=self.note, omit_fields=self.omit_fields)