## $Id: paydirectbrowser.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 (
    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

    @property
    def item_code(self):
        return '01' # for testing

    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
        result_xml = create_paydirect_booking(
            self.merchant_id, self.context, self.item_code, self.gateway_host,
            self.gateway_url, True)
        if result_xml.startswith('Connection error'):
            IPayer(self.context).payer.writeLogMessage(self, result_xml)
            return result_xml
        doc=parseString(result_xml)
        if not doc.getElementsByTagName('ResponseCode'):
            IPayer(self.context).payer.writeLogMessage(self, 'invalid callback')
            return _('Invalid callback from Interswitch')
        rc = doc.getElementsByTagName('ResponseCode')[0].firstChild.data
        IPayer(self.context).payer.writeLogMessage(self, 'response code: %s' % rc)
        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
        # 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'
        error = self.init_update()
        if error:
            self.flash(error, type='danger')
            self.redirect(self.url(self.context, '@@index'))
            return
        return

    @action('Requery now', style='primary')
    def fetch(self):
        success, msg, log = fetch_booking_details(
            self.context, self.merchant_id, self.gateway_host,
            self.gateway_url, self.https)
        IPayer(self.context).payer.writeLogMessage(self, log)
        if not success:
            self.flash(msg, type='warning')
            self.redirect(self.url(self.context, '@@index'))
            return
        write_payments_log(IPayer(self.context).id, self.context)
        flashtype, msg, log = IPayer(self.context).doAfterPayment()
        if log is not None:
            IPayer(self.context).payer.writeLogMessage(self, log)
        self.flash(msg, type=flashtype)
        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
        # 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'
        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.")
        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 """<br /><br />
Go to your bank and make your PAYDirect payment with the reference number <strong>%s</strong>.
""" % 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 """<br /><br />
Go to your bank and make your PAYDirect payment with the reference number <strong>%s</strong>.
""" % 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)
