## $Id: browser.py 16484 2021-05-19 07:47:21Z henrik $ ## ## Copyright (C) 2012 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.component import getUtility from zope.security import checkPermission 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.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant from kofacustom.nigeria.interswitch.helpers import ( query_interswitch, write_payments_log, fetch_booking_details) 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 # Buttons def module_activated(session, payment): if payment.r_company and payment.r_company != 'interswitch': return False try: return getattr(grok.getSite()['configuration'][str(session)], 'interswitch_enabled', True) except KeyError: session = datetime.now().year try: return getattr(grok.getSite()['configuration'][str(session)], 'interswitch_enabled', True) except KeyError: return False class InterswitchActionButtonStudent(ManageActionButton): grok.order(1) grok.context(INigeriaOnlinePayment) grok.view(OPDPStudent) grok.require('waeup.payStudent') icon = 'actionicon_pay.png' text = _('Pay via Interswitch CollegePAY') target = 'goto_interswitch' @property def target_url(self): if not module_activated( self.context.student.current_session, self.context): return '' if self.context.p_state != 'unpaid': return '' return self.view.url(self.view.context, self.target) class InterswitchActionButtonApplicant(InterswitchActionButtonStudent): grok.view(OPDPApplicant) grok.require('waeup.payApplicant') @property def target_url(self): if not 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 InterswitchRequestWebserviceActionButtonStudent(ManageActionButton): grok.order(2) grok.context(INigeriaOnlinePayment) grok.view(OPDPStudent) grok.require('waeup.payStudent') icon = 'actionicon_call.png' text = _('Requery CollegePAY History') target = 'request_webservice' @property def target_url(self): if not module_activated( self.context.student.current_session, self.context): return '' if self.context.p_state in ('paid', 'waived', 'scholarship'): return '' return self.view.url(self.view.context, self.target) class InterswitchRequestWebserviceActionButtonApplicant( InterswitchRequestWebserviceActionButtonStudent): grok.view(OPDPApplicant) grok.require('waeup.payApplicant') @property def target_url(self): if not module_activated( self.context.__parent__.__parent__.year, self.context): return '' if self.context.p_state in ('paid', 'waived', 'scholarship'): return '' return self.view.url(self.view.context, self.target) class InterswitchVerifyWebserviceActionButtonStudent(ManageActionButton): grok.order(3) grok.context(INigeriaOnlinePayment) grok.view(OPDPStudent) grok.require('waeup.manageStudent') icon = 'actionicon_call.png' text = _('Verify Payment') target = 'verify_payment' @property def target_url(self): if not module_activated( self.context.student.current_session, self.context): return '' if self.context.p_state != 'paid' \ or self.context.r_company != u'interswitch': return '' return self.view.url(self.view.context, self.target) class InterswitchVerifyWebserviceActionButtonApplicant( InterswitchVerifyWebserviceActionButtonStudent): grok.view(OPDPApplicant) grok.require('waeup.manageApplication') @property def target_url(self): if not module_activated( self.context.__parent__.__parent__.year, self.context): return '' if self.context.p_state != 'paid' \ or self.context.r_company != u'interswitch': return '' return self.view.url(self.view.context, self.target) # Webservice request views class InterswitchPaymentRequestWebservicePageStudent(UtilityView, grok.View): """ Request webservice view for the CollegePAY gateway """ grok.context(INigeriaStudentOnlinePayment) grok.name('request_webservice') grok.require('waeup.payStudent') product_id = None gateway_host = None gateway_url = None https = True mac = None def update(self): if not module_activated( self.context.student.current_session, self.context): return if self.context.p_state in ('paid', 'waived', 'scholarship'): self.flash(_('This ticket has already been paid.'), type='danger') return student = self.context.student success, msg, log = query_interswitch( self.context, self.product_id, self.gateway_host, self.gateway_url, self.https, self.mac, False) student.writeLogMessage(self, log) if not success: self.flash(msg, type='danger') 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) return def render(self): self.redirect(self.url(self.context, '@@index')) return class InterswitchPaymentRequestWebservicePageApplicant(UtilityView, grok.View): """ Request webservice view for the CollegePAY gateway """ grok.context(INigeriaApplicantOnlinePayment) grok.name('request_webservice') grok.require('waeup.payApplicant') product_id = None gateway_host = None gateway_url = None https = True mac = None def update(self): if not module_activated( self.context.__parent__.__parent__.year, self.context): return if self.context.p_state == 'paid': self.flash(_('This ticket has already been paid.'), type='danger') return applicant = self.context.__parent__ success, msg, log = query_interswitch( self.context, self.product_id, self.gateway_host, self.gateway_url, self.https, self.mac, False) applicant.writeLogMessage(self, log) if not success: self.flash(msg, type='danger') 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 def render(self): self.redirect(self.url(self.context.__parent__, 'edit')) return class InterswitchPaymentVerifyWebservicePageStudent(UtilityView, grok.View): """ Verify payment view for the CollegePAY gateway """ grok.context(INigeriaStudentOnlinePayment) grok.name('verify_payment') grok.require('waeup.manageStudent') product_id = None gateway_host = None gateway_url = None https = True mac = None def update(self): if not module_activated( self.context.student.current_session, self.context): return if self.context.p_state != 'paid' \ or self.context.r_company != u'interswitch': self.flash(_('This ticket has not been paid.'), type='danger') return student = self.context.student success, msg, log = query_interswitch( self.context, self.product_id, self.gateway_host, self.gateway_url, self.https, self.mac, True) student.writeLogMessage(self, log) if not success: self.flash(msg, type='danger') return self.flash(msg) return def render(self): self.redirect(self.url(self.context, '@@index')) return class InterswitchPaymentVerifyWebservicePageApplicant(UtilityView, grok.View): """ Verify payment view for the CollegePAY gateway """ grok.context(INigeriaApplicantOnlinePayment) grok.name('verify_payment') grok.require('waeup.manageApplication') product_id = None gateway_host = None gateway_url = None https = True mac = None def update(self): if not module_activated( self.context.__parent__.__parent__.year, self.context): return if self.context.p_state != 'paid' \ or self.context.r_company != u'interswitch': self.flash(_('This ticket has not been paid.'), type='danger') return applicant = self.context.__parent__ success, msg, log = query_interswitch( self.context, self.product_id, self.gateway_host, self.gateway_url, self.https, self.mac, True) applicant.writeLogMessage(self, log) if not success: self.flash(msg, type='danger') return self.flash(msg) return def render(self): self.redirect(self.url(self.context, '@@index')) return # Forwarding pages class InterswitchPageStudent(KofaPage): """ View which sends a POST request to the Interswitch CollegePAY payment gateway. """ grok.context(INigeriaOnlinePayment) grok.name('goto_interswitch') grok.template('student_goto_interswitch') grok.require('waeup.payStudent') label = _('Submit data to CollegePAY') submit_button = _('Submit') action = None site_name = None currency = None pay_item_id = None product_id = None xml_data = None hashvalue = None gateway_amt = GATEWAY_AMT def init_update(self): if self.context.p_state == 'paid': return _("Payment ticket can't be re-sent to CollegePAY.") now = datetime.utcnow() if self.context.creation_date.tzinfo is not None: # That's bad. Please store timezone-naive datetimes only! now = self.context.creation_date.tzinfo.localize(now) time_delta = now - self.context.creation_date if time_delta.days > 7: return _("This payment ticket is too old. Please create a new ticket.") if self.context.r_company and self.context.r_company != 'interswitch': return _("Payment ticket has been used for another payment gateway.") student = self.context.student certificate = getattr(student['studycourse'],'certificate',None) if certificate is None: return _("Study course data are incomplete.") kofa_utils = getUtility(IKofaUtils) student_utils = getUtility(IStudentsUtils) if student_utils.samePaymentMade(student, self.context.p_category, self.context.p_item, self.context.p_session): return _("This type of payment has already been made.") xmldict = {} if certificate is not None: xmldict['department'] = certificate.__parent__.__parent__.code xmldict['faculty'] = certificate.__parent__.__parent__.__parent__.code else: xmldict['department'] = None xmldict['faculty'] = None self.category = self.context.category tz = kofa_utils.tzinfo self.local_date_time = to_timezone( self.context.creation_date, tz).strftime("%Y-%m-%d %H:%M:%S %Z") self.site_redirect_url = self.url(self.context, 'request_webservice') self.student = student self.xmldict = xmldict return def update(self): if not 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')) # 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' self.amount_auth = int(100 * self.context.amount_auth) return class InterswitchPageApplicant(KofaPage): """ View which sends a POST request to the Interswitch CollegePAY payment gateway. """ grok.context(INigeriaApplicantOnlinePayment) grok.require('waeup.payApplicant') grok.template('applicant_goto_interswitch') grok.name('goto_interswitch') label = _('Submit data to CollegePAY') submit_button = _('Submit') action = None site_name = None currency = None pay_item_id = None product_id = None xml_data = None hashvalue = None gateway_amt = GATEWAY_AMT def init_update(self): if self.context.p_state != 'unpaid': return _("Payment ticket can't be re-sent to CollegePAY.") if self.context.__parent__.__parent__.expired \ and self.context.__parent__.__parent__.strict_deadline: return _("Payment ticket can't be sent to CollegePAY. " "Application period has expired.") if self.context.r_company and self.context.r_company != 'interswitch': return _("Payment ticket has been used for another payment gateway.") tz = getUtility(IKofaUtils).tzinfo time_delta = datetime.utcnow() - self.context.creation_date if time_delta.days > 7: return _("This payment ticket is too old. Please create a new ticket.") self.applicant = self.context.__parent__ self.category = self.context.category tz = getUtility(IKofaUtils).tzinfo self.local_date_time = to_timezone( self.context.creation_date, tz).strftime("%Y-%m-%d %H:%M:%S %Z") self.site_redirect_url = self.url(self.context, 'request_webservice') return def update(self): if not 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')) # 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' self.amount_auth = int(100 * self.context.amount_auth) return