## $Id: webcheckoutbrowser.py 16587 2021-08-31 06:28:35Z 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.payments.interfaces import IPayer 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 ( write_payments_log, confirm_transaction) 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 ( MERCHANT_ID) from kofacustom.nigeria.interfaces import MessageFactory as _ GATEWAY_AMT = 0.0 grok.templatedir('browser_templates') def webcheckout_module_activated(session, payment): if payment.p_currency != 'NGN': return False if payment.r_company and payment.r_company != 'interswitch': return False try: return getattr(grok.getSite()['configuration'][str(session)], 'interswitch_webcheckout_enabled', False) except KeyError: session = datetime.now().year try: return getattr(grok.getSite()['configuration'][str(session)], 'interswitch_webcheckout_enabled', False) except KeyError: return False # Buttons class WebcheckoutActionButtonStudent(ManageActionButton): grok.context(INigeriaOnlinePayment) grok.view(OPDPStudent) grok.require('waeup.payStudent') grok.order(10) icon = 'actionicon_pay.png' text = _('Pay via Interswitch WebCheckout') target = 'webcheckout' @property def target_url(self): if not webcheckout_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 WebcheckoutActionButtonApplicant(WebcheckoutActionButtonStudent): grok.view(OPDPApplicant) grok.require('waeup.payApplicant') @property def target_url(self): if not webcheckout_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 WebCheckoutConfirmTransactionActionButtonStudent(ManageActionButton): grok.order(11) grok.context(INigeriaOnlinePayment) grok.view(OPDPStudent) grok.require('waeup.payStudent') icon = 'actionicon_call.png' text = _('Confirm WebCheckout Transaction') target = 'confirm_transaction' @property def target_url(self): if not webcheckout_module_activated( self.context.student.current_session, self.context): return '' if self.context.amount_auth == 0: return '' if self.context.p_state in ('paid', 'waived', 'scholarship'): return '' return self.view.url(self.view.context, self.target) class WebCheckoutConfirmTransactionActionButtonApplicant( WebCheckoutConfirmTransactionActionButtonStudent): grok.view(OPDPApplicant) grok.require('waeup.payApplicant') @property def target_url(self): if not webcheckout_module_activated( self.context.__parent__.__parent__.year, self.context): return '' if self.context.amount_auth == 0: return '' if self.context.p_state in ('paid', 'waived', 'scholarship'): return '' return self.view.url(self.view.context, self.target) # Forwarding pages class WebCheckoutPageStudent(KofaPage): """ View which sends a POST request to the Interswitch WebCheckout payment gateway. """ grok.context(INigeriaOnlinePayment) grok.name('webcheckout') grok.template('student_goto_webcheckout') grok.require('waeup.payStudent') label = _('Submit data to Interswitch') submit_button = _('Submit') action = None currency = None pay_item_id = None merchant_code = None gateway_amt = GATEWAY_AMT def init_update(self): if self.context.p_state == 'paid': return _("Payment ticket can't be re-sent to WebCheckout.") 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 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 = {} 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, 'confirm_transaction') self.student = student return def update(self): if not webcheckout_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 WebCheckoutPageApplicant(KofaPage): """ View which sends a POST request to the Interswitch WebCheckout payment gateway. """ grok.context(INigeriaApplicantOnlinePayment) grok.require('waeup.payApplicant') grok.template('applicant_goto_webcheckout') grok.name('webcheckout') label = _('Submit data to Interswitch') submit_button = _('Submit') action = None currency = None pay_item_id = None merchant_code = None gateway_amt = GATEWAY_AMT split_accounts = None def init_update(self): if self.context.p_state != 'unpaid': return _("Payment ticket can't be re-sent to WebCheckout.") if self.context.__parent__.__parent__.expired \ and self.context.__parent__.__parent__.strict_deadline: return _("Payment ticket can't be sent to WebCheckout. " "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, 'confirm_transaction') return def update(self): if not webcheckout_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 # Webservice request views class WebCheckoutConfirmTransactionApplicant(UtilityView, grok.View): """ Request webservice view for the WebCheckout gateway """ grok.context(INigeriaApplicantOnlinePayment) grok.name('confirm_transaction') grok.require('waeup.payApplicant') merchant_code = None gateway_host = None gateway_url = None https = True split_accounts = None mac = '' def update(self): if not webcheckout_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 = confirm_transaction( self.context, self.merchant_code, self.gateway_host, self.gateway_url, self.https, self.mac) 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 WebCheckoutConfirmTransactionStudent(UtilityView, grok.View): """ Request webservice view for the WebCheckout gateway """ grok.context(INigeriaStudentOnlinePayment) grok.name('confirm_transaction') grok.require('waeup.payStudent') merchant_code = None gateway_host = None gateway_url = None https = True mac = '' def update(self): if not webcheckout_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 = confirm_transaction( self.context, self.merchant_code, self.gateway_host, self.gateway_url, self.https, self.mac) 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