## $Id: browser.py 8710 2012-06-13 13:56:50Z 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
##
from datetime import datetime
import httplib
import urllib
from xml.dom.minidom import parseString
import grok
from zope.component import getUtility
from zope.catalog.interfaces import ICatalog
from waeup.kofa.interfaces import IUniversity
from waeup.kofa.payments.interfaces import IPaymentWebservice
from waeup.kofa.browser.layout import KofaPage, UtilityView
from waeup.kofa.students.viewlets import ApprovePaymentActionButton as APABStudent
from waeup.kofa.applicants.viewlets import ApprovePaymentActionButton as APABApplicant
from waeup.aaue.interfaces import academic_sessions_vocab
from waeup.aaue.interfaces import MessageFactory as _
from waeup.aaue.students.interfaces import ICustomStudentOnlinePayment
from waeup.aaue.applicants.interfaces import ICustomApplicantOnlinePayment

# Kofa's webservice

class KofaFeeRequest(grok.View):
    grok.context(IUniversity)
    grok.name('feerequest')
    grok.require('waeup.Public')

    def update(self, PAYEE_ID=None):
        cat = getUtility(ICatalog, name='payments_catalog')
        results = list(cat.searchResults(p_id=(PAYEE_ID, PAYEE_ID)))
        if len(results) != 1:
            self.output = '-1'
        else:
            try:
                owner = IPaymentWebservice(results[0])
                full_name = owner.display_fullname
                matric_no = owner.id
                faculty = owner.faculty
                department = owner.department
            except (TypeError, AttributeError):
                self.output = '-1'
                return
            amount = results[0].amount_auth
            payment_type = results[0].category
            programme_type = results[0].p_item
            academic_session = academic_sessions_vocab.getTerm(
                results[0].p_session).title
            status = results[0].p_state
            self.output = ('FULL_NAME1=%s&MATRIC_NO1=%s&' +
                'ACADEMIC_SESSION1=%s&PAYMENT_TYPE1=%s&' +
                'PAYMENT_TYPE3=&FACULTY1=%s&' +
                'DEPARTMENT1=%s&PROGRAMME_TYPE1=%s&' +
                'RETURN_TYPE1=&FEE_AMOUNT1=%s&' +
                'TRANSACTION_STATUS1=%s') % (full_name, matric_no,
                academic_session, payment_type, faculty, department,
                programme_type, amount, status)
        return

    def render(self):
        return self.output


# Requerying eTranzact payments

#TERMINAL_ID = '0330000046'
#QUERY_URL =   'https://www.etranzact.net/Query/queryPayoutletTransaction.jsp'

# Test environment
QUERY_URL =   'http://demo.etranzact.com:8080/WebConnect/queryPayoutletTransaction.jsp'
TERMINAL_ID = '5009892287'

def query_etranzact(confirmation_number, payment):
    
    postdict = {}
    postdict['TERMINAL_ID'] = TERMINAL_ID
    #postdict['RESPONSE_URL'] = 'http://dummy'
    postdict['CONFIRMATION_NO'] = confirmation_number
    data = urllib.urlencode(postdict)
    payment.conf_number = confirmation_number
    try:
        f = urllib.urlopen(url=QUERY_URL, data=data)
        success = f.read()
        success = success.replace('\r\n','')
        if 'COL1' not in success:
            msg = _('Invalid or unsuccessful callback: ${a}',
                mapping = {'a': success})
            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
            payment.p_state = 'failed'
            return False, msg, log
        success = success.replace('%20',' ').split('&')
        # We expect at least two parameters
        if len(success) < 2:
            msg = _('Invalid callback: ${a}', mapping = {'a': success})
            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
            payment.p_state = 'failed'
            return False, msg, log
        try:
            success_dict = dict([tuple(i.split('=')) for i in success])
        except ValueError:
            msg = _('Invalid callback: ${a}', mapping = {'a': success})
            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
            payment.p_state = 'failed'
            return False, msg, log
    except IOError:
        msg = _('eTranzact IOError')
        log = 'eTranzact IOError'
        return False, msg, log
    payment.r_code = u'ET'
    payment.r_desc = u'%s' % success_dict.get('TRANS_DESCR')
    payment.r_amount_approved = float(success_dict.get('TRANS_AMOUNT',0.0))
    payment.r_card_num = None
    payment.r_pay_reference = u'%s' % success_dict.get('RECEIPT_NO')
    if payment.r_amount_approved != payment.amount_auth:
        msg = _('Wrong amount')
        log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
        payment.p_state = 'failed'
        return False, msg, log
    tcode = payment.p_id
    tcode = tcode[len(tcode)-8:len(tcode)]
    col1 = success_dict.get('COL1')
    col1 = col1[len(col1)-8:len(col1)]
    if tcode != col1:
        msg = _('Wrong transaction code')
        log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
        payment.p_state = 'failed'
        return False, msg, log
    log = 'valid callback for payment %s: %s' % (payment.p_id, success)
    msg = _('Successful callback received')
    payment.p_state = 'paid'
    payment.payment_date = datetime.utcnow()
    return True, msg, log

class EtranzactEnterPinActionButtonApplicant(APABApplicant):
    grok.context(ICustomApplicantOnlinePayment)
    grok.require('waeup.payApplicant')
    grok.order(3)
    icon = 'actionicon_call.png'
    text = _('Query eTranzact History')
    target = 'enterpin'

class EtranzactEnterPinActionButtonStudent(APABStudent):
    grok.context(ICustomStudentOnlinePayment)
    grok.require('waeup.payStudent')
    grok.order(3)
    icon = 'actionicon_call.png'
    text = _('Query eTranzact History')
    target = 'enterpin'

class EtranzactEnterPinPageStudent(KofaPage):
    """
    """
    grok.context(ICustomStudentOnlinePayment)
    grok.name('enterpin')
    grok.template('enterpin')
    grok.require('waeup.payStudent')

    buttonname = _('Submit to eTranzact')
    label = _('Requery eTranzact History')
    action = 'query_history'

class EtranzactEnterPinPageApplicant(EtranzactEnterPinPageStudent):
    """
    """
    grok.require('waeup.payApplicant')
    grok.context(ICustomApplicantOnlinePayment)

class EtranzactQueryHistoryPageStudent(UtilityView, grok.View):
    """ Query history of eTranzact payments
    """
    grok.context(ICustomStudentOnlinePayment)
    grok.name('query_history')
    grok.require('waeup.payStudent')

    def update(self, confirmation_number=None):
        ob_class = self.__implemented__.__name__
        if self.context.p_state == 'paid':
            self.flash(_('This ticket has already been paid.'))
            return
        student = self.context.getStudent()
        success, msg, log = query_etranzact(confirmation_number,self.context)
        student.loggerInfo(ob_class, log)
        if not success:
            self.flash(msg)
            return
        success, msg, log = self.context.doAfterStudentPayment()
        if log is not None:
            student.loggerInfo(ob_class, log)
        self.flash(msg)
        return

    def render(self):
        self.redirect(self.url(self.context, '@@index'))
        return

class EtranzactQueryHistoryPageApplicant(UtilityView, grok.View):
    """ Query history of eTranzact payments
    """
    grok.context(ICustomApplicantOnlinePayment)
    grok.name('query_history')
    grok.require('waeup.payApplicant')

    def update(self, confirmation_number=None):
        ob_class = self.__implemented__.__name__
        if self.context.p_state == 'paid':
            self.flash(_('This ticket has already been paid.'))
            return
        applicant = self.context.__parent__
        success, msg, log = query_etranzact(confirmation_number,self.context)
        applicant.loggerInfo(ob_class, log)
        if not success:
            self.flash(msg)
            return
        success, msg, log = self.context.doAfterApplicantPayment()
        if log is not None:
            applicant.loggerInfo(ob_class, log)
        self.flash(msg)
        return

    def render(self):
        self.redirect(self.url(self.context, '@@index'))
        return
