## $Id: browser.py 17248 2022-12-28 15:26:56Z 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.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_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 ''
        if self.context.amount_auth == 0:
            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 ''
        if self.context.amount_auth == 0:
            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.amount_auth == 0:
            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.amount_auth == 0:
            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

