## $Id: studentsbrowser.py 17248 2022-12-28 15:26:56Z henrik $
##
## Copyright (C) 2017 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
import hashlib
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
from waeup.kofa.browser.viewlets import ManageActionButton
from waeup.kofa.students.interfaces import IStudentsUtils
from waeup.kofa.students.browser import OnlinePaymentDisplayFormPage as OPDPStudent
from kofacustom.nigeria.remita.helpers import (
    get_JSON_POST_response, query_remita, write_payments_log)
from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
from kofacustom.nigeria.interfaces import MessageFactory as _

from kofacustom.nigeria.remita.tests import (
    MERCHANTID, HOST, HTTPS, API_KEY, SERVICETYPEID, GATEWAY_AMT)

grok.templatedir('browser_templates')

def module_activated(session, payment):
    if payment.p_currency != 'NGN':
        return False
    if payment.r_company and payment.r_company != 'remita':
        return False
    try:
        return getattr(grok.getSite()['configuration'][str(session)],
            'remita_enabled', False)
    except KeyError:
        session = datetime.now().year
        try:
            return getattr(grok.getSite()['configuration'][str(session)],
                'remita_enabled', False)
        except KeyError:
            return False

# Buttons

class RemitaActionButtonStudent(ManageActionButton):
    grok.order(5)
    grok.context(INigeriaOnlinePayment)
    grok.view(OPDPStudent)
    grok.require('waeup.payStudent')
    icon = 'actionicon_pay.png'
    text = _('Pay via Remita')
    target = 'goto_remita'

    @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 RemitaRequestPaymentStatusActionButtonStudent(ManageActionButton):
    grok.order(6)
    grok.context(INigeriaOnlinePayment)
    grok.view(OPDPStudent)
    grok.require('waeup.payStudent')
    icon = 'actionicon_call.png'
    text = _('Requery Remita Payment Status')
    target = 'request_payment_status'

    @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 RemitaVerifyPaymentStatusActionButtonStudent(ManageActionButton):
    grok.order(3)
    grok.context(INigeriaOnlinePayment)
    grok.view(OPDPStudent)
    grok.require('waeup.manageStudent')
    icon = 'actionicon_call.png'
    text = _('Verify Remita Payment Status')
    target = 'verify_payment_status'

    @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'remita':
            return ''
        return self.view.url(self.view.context, self.target)

# Webservice request views

class RemitaRequestPaymentStatusPageStudent(UtilityView, grok.View):
    """ Request webservice view for the Remita gateway.
    """
    grok.context(INigeriaStudentOnlinePayment)
    grok.name('request_payment_status')
    grok.require('waeup.payStudent')

    merchantId = MERCHANTID
    host = HOST
    https = HTTPS
    api_key = API_KEY

    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
        if self.context.p_state in ('paid', 'waived', 'scholarship'):
            self.flash(_('This ticket has already been paid.'), type='danger')
            return
        student = self.context.student
        RRR = self.context.r_pay_reference
        if not RRR:
            self.flash(_('Remita Retrieval Reference not found.'), type='danger')
            return
        # Remita sends a POST request which may contain more information
        # if a payment was not successful.
        resp = self.request.form
        if resp and resp.get('statuscode') not in (None, '025', '00', '01'):
            self.flash('Transaction status message from Remita: %s'
                % resp.get('status'), type='warning')
        success, msg, log = query_remita(
            self.context,
            self.merchantId,
            self.api_key,
            RRR,
            self.host,
            self.https,
            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 RemitaVerifyPaymentStatusPageStudent(UtilityView, grok.View):
    """ Request webservice view for the Remita gateway.
    """
    grok.context(INigeriaStudentOnlinePayment)
    grok.name('verify_payment_status')
    grok.require('waeup.manageStudent')

    merchantId = MERCHANTID
    host = HOST
    https = HTTPS
    api_key = API_KEY

    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
        if self.context.p_state  != 'paid' \
            or self.context.r_company != u'remita':
            self.flash(_('This ticket has not been paid.'), type='danger')
            return
        student = self.context.student
        RRR = self.context.r_pay_reference
        if not RRR:
            self.flash(_('Remita Retrieval Reference not found.'), type='danger')
            return
        # Remita sends a POST request which may contain more information
        # if a payment was not successful.
        resp = self.request.form
        if resp and resp.get('statuscode') not in (None, '025', '00', '01'):
            self.flash('Transaction status message from Remita: %s'
                % resp.get('status'), type='warning')
        success, msg, log = query_remita(
            self.context,
            self.merchantId,
            self.api_key,
            RRR,
            self.host,
            self.https,
            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


# Forwarding pages

class RemitaPageStudent(KofaPage):
    """ View which sends a POST request to the Remita payment gateway.
    """
    grok.context(INigeriaOnlinePayment)
    grok.name('goto_remita')
    grok.template('goto_remita')
    grok.require('waeup.payStudent')
    label = _('Pay via Remita')
    submit_button = _('Pay now')

    merchantId = MERCHANTID
    host = HOST
    https = HTTPS
    api_key = API_KEY
    serviceTypeId = SERVICETYPEID
    gateway_amt = GATEWAY_AMT

    #orderId = '3456346346'
    init_url = '/remita/ecomm/split/init.reg'
    amount='1000'
    lineitems = (
                  {"lineItemsId":"itemid1","beneficiaryName":"Klaus Mueller",
                  "beneficiaryAccount":"6020067886","bankCode":"011",
                  "beneficiaryAmount":"500","deductFeeFrom":"1"},
                  {"lineItemsId":"itemid2","beneficiaryName":"Werner Rumm",
                  "beneficiaryAccount":"0360883515","bankCode":"050",
                  "beneficiaryAmount":"500","deductFeeFrom":"0"}
                )

    @property
    def action(self):
        if self.https:
            return 'https://' + self.host + '/remita/ecomm/finalize.reg'
        return 'http://' + self.host + '/remita/ecomm/finalize.reg'

    def init_update(self):
        if self.context.r_pay_reference or self.context.p_state == 'paid':
            return _("Payment ticket can't be re-sent to Remita.")
        if self.context.r_company and self.context.r_company != 'remita':
            return _("Payment ticket has been used for another payment gateway.")
        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.")
        certificate = getattr(self.context.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(self.context.student, self.context.p_category,
            self.context.p_item, self.context.p_session):
            return _("This type of payment has already been made.")
        self.responseurl = self.url(self.context, 'request_payment_status')
        resp = get_JSON_POST_response(
            merchantId=self.merchantId,
            serviceTypeId=self.serviceTypeId,
            api_key=self.api_key,
            orderId=self.orderId,
            amount=self.amount,
            responseurl=self.responseurl,
            host=self.host,
            url=self.init_url,
            https=self.https,
            fullname=self.context.student.display_fullname,
            email=self.context.student.email,
            lineitems=self.lineitems)
        if resp.get('error'):
            return resp.get('error')
        if resp.get('statuscode') not in ('021', '025', '055'):
            return 'RRR generation message from Remita: ' + resp.get('status')
        self.rrr = self.context.r_pay_reference = resp['RRR'].rstrip()
        hashargs = 	self.merchantId + self.rrr + self.api_key
        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
        self.customer = self.context.student
        self.customer.writeLogMessage(self,
            'RRR retrieved: %s, ServiceTypeId: %s'
            % (self.rrr, self.serviceTypeId))
        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
        self.orderId = self.context.p_id
        error = self.init_update()
        if error:
            self.flash(error, type='danger')
            self.redirect(self.url(self.context, '@@index'))
            return
        # Already now it becomes a Remita 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'remita'
        self.amount_auth = int(100 * self.context.amount_auth)
        return
