## $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 """<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)
