source: main/waeup.aaue/trunk/src/waeup/aaue/etranzact/browser.py @ 8755

Last change on this file since 8755 was 8754, checked in by Henrik Bettermann, 13 years ago

Disable QUERY_STRING processing until eTranzact has replied to Uli's mail.

  • Property svn:keywords set to Id
File size: 9.5 KB
RevLine 
[7929]1## $Id: browser.py 8754 2012-06-18 17:02:17Z henrik $
2##
3## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18from datetime import datetime
19import httplib
20import urllib
21from xml.dom.minidom import parseString
22import grok
[8704]23from zope.component import getUtility
24from zope.catalog.interfaces import ICatalog
[8698]25from waeup.kofa.interfaces import IUniversity
[8704]26from waeup.kofa.payments.interfaces import IPaymentWebservice
[7929]27from waeup.kofa.browser.layout import KofaPage, UtilityView
[8430]28from waeup.kofa.students.viewlets import ApprovePaymentActionButton as APABStudent
29from waeup.kofa.applicants.viewlets import ApprovePaymentActionButton as APABApplicant
[8710]30from waeup.aaue.interfaces import academic_sessions_vocab
[8444]31from waeup.aaue.interfaces import MessageFactory as _
32from waeup.aaue.students.interfaces import ICustomStudentOnlinePayment
33from waeup.aaue.applicants.interfaces import ICustomApplicantOnlinePayment
[7929]34
[8746]35ACCEPTED_IP = None
36
[8698]37# Kofa's webservice
38
39class KofaFeeRequest(grok.View):
40    grok.context(IUniversity)
41    grok.name('feerequest')
42    grok.require('waeup.Public')
43
44    def update(self, PAYEE_ID=None):
[8746]45        real_ip = self.request.get('HTTP_X_FORWARDED_FOR', None)
46        if real_ip  and ACCEPTED_IP:
47            if real_ip != ACCEPTED_IP:
48                self.output = '-4'
49                return
[8754]50
51        # It seems eTranzact sends a POST request with an empty body but the URL
52        # contains a query string. So it's actually a GET request pretended
53        # to be a POST request. Although this does not comply with the
54        # RFC 2616 HTTP guidelines we may try to fetch the id from the QUERY_STRING
55        # value of the request.
56
57        #if PAYEE_ID is None:
58        #    try:
59        #        PAYEE_ID = self.request['QUERY_STRING'].split('=')[1]
60        #    except:
61        #        self.output = '-2'
62        #        return
63
[8704]64        cat = getUtility(ICatalog, name='payments_catalog')
65        results = list(cat.searchResults(p_id=(PAYEE_ID, PAYEE_ID)))
66        if len(results) != 1:
67            self.output = '-1'
[8746]68            return
69        try:
70            owner = IPaymentWebservice(results[0])
71            full_name = owner.display_fullname
72            matric_no = owner.id
73            faculty = owner.faculty
74            department = owner.department
75        except (TypeError, AttributeError):
76            self.output = '-3'
77            return
78        amount = results[0].amount_auth
79        payment_type = results[0].category
80        programme_type = results[0].p_item
81        academic_session = academic_sessions_vocab.getTerm(
82            results[0].p_session).title
83        status = results[0].p_state
84        self.output = (
85            'FULL_NAME=%s&' +
86            'FACULTY=%s&' +
87            'DEPARTMENT=%s&' +
88            'RETURN_TYPE=%s&' +
89            'PROGRAMME_TYPE=%s&' +
90            'PAYMENT_TYPE=%s&' +
91            'ACADEMIC_SESSION=%s&' +
92            'MATRIC_NO=%s&' +
93            'FEE_AMOUNT=%s&' +
94            'TRANSACTION_STATUS=%s') % (full_name, faculty,
95            department, PAYEE_ID, programme_type, payment_type,
96            academic_session, matric_no, amount, status)
[8698]97        return
98
99    def render(self):
100        return self.output
101
102
103# Requerying eTranzact payments
104
[8682]105#TERMINAL_ID = '0330000046'
[8680]106#QUERY_URL =   'https://www.etranzact.net/Query/queryPayoutletTransaction.jsp'
[8259]107
[8680]108# Test environment
109QUERY_URL =   'http://demo.etranzact.com:8080/WebConnect/queryPayoutletTransaction.jsp'
[8734]110TERMINAL_ID = '5009892289'
[8680]111
[8430]112def query_etranzact(confirmation_number, payment):
113   
[8247]114    postdict = {}
115    postdict['TERMINAL_ID'] = TERMINAL_ID
116    #postdict['RESPONSE_URL'] = 'http://dummy'
117    postdict['CONFIRMATION_NO'] = confirmation_number
118    data = urllib.urlencode(postdict)
[8682]119    payment.conf_number = confirmation_number
[8247]120    try:
121        f = urllib.urlopen(url=QUERY_URL, data=data)
122        success = f.read()
[8432]123        success = success.replace('\r\n','')
[8247]124        if 'COL1' not in success:
[8430]125            msg = _('Invalid or unsuccessful callback: ${a}',
126                mapping = {'a': success})
127            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
[8247]128            payment.p_state = 'failed'
[8430]129            return False, msg, log
[8247]130        success = success.replace('%20',' ').split('&')
131        # We expect at least two parameters
132        if len(success) < 2:
[8430]133            msg = _('Invalid callback: ${a}', mapping = {'a': success})
134            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
[8247]135            payment.p_state = 'failed'
[8430]136            return False, msg, log
[8247]137        try:
138            success_dict = dict([tuple(i.split('=')) for i in success])
139        except ValueError:
[8430]140            msg = _('Invalid callback: ${a}', mapping = {'a': success})
141            log = 'invalid callback for payment %s: %s' % (payment.p_id, success)
[8247]142            payment.p_state = 'failed'
[8430]143            return False, msg, log
[8247]144    except IOError:
[8430]145        msg = _('eTranzact IOError')
146        log = 'eTranzact IOError'
147        return False, msg, log
[8247]148    payment.r_code = u'ET'
149    payment.r_desc = u'%s' % success_dict.get('TRANS_DESCR')
150    payment.r_amount_approved = float(success_dict.get('TRANS_AMOUNT',0.0))
151    payment.r_card_num = None
152    payment.r_pay_reference = u'%s' % success_dict.get('RECEIPT_NO')
153    if payment.r_amount_approved != payment.amount_auth:
[8430]154        msg = _('Wrong amount')
155        log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
[8247]156        payment.p_state = 'failed'
[8430]157        return False, msg, log
[8717]158    #tcode = payment.p_id
159    #tcode = tcode[len(tcode)-8:len(tcode)]
[8247]160    col1 = success_dict.get('COL1')
[8717]161    #col1 = col1[len(col1)-8:len(col1)]
162    #if tcode != col1:
163    if payment.p_id != col1:
164        #msg = _('Wrong transaction code')
165        msg = _('Wrong payment id')
[8430]166        log = 'wrong callback for payment %s: %s' % (payment.p_id, success)
[8247]167        payment.p_state = 'failed'
[8430]168        return False, msg, log
169    log = 'valid callback for payment %s: %s' % (payment.p_id, success)
170    msg = _('Successful callback received')
[8247]171    payment.p_state = 'paid'
[8433]172    payment.payment_date = datetime.utcnow()
[8430]173    return True, msg, log
[8247]174
[8430]175class EtranzactEnterPinActionButtonApplicant(APABApplicant):
[8253]176    grok.context(ICustomApplicantOnlinePayment)
[8430]177    grok.require('waeup.payApplicant')
[8259]178    grok.order(3)
[7929]179    icon = 'actionicon_call.png'
180    text = _('Query eTranzact History')
[7976]181    target = 'enterpin'
[7929]182
[8430]183class EtranzactEnterPinActionButtonStudent(APABStudent):
[8253]184    grok.context(ICustomStudentOnlinePayment)
[8430]185    grok.require('waeup.payStudent')
[8259]186    grok.order(3)
[8247]187    icon = 'actionicon_call.png'
188    text = _('Query eTranzact History')
189    target = 'enterpin'
190
191class EtranzactEnterPinPageStudent(KofaPage):
[7976]192    """
193    """
[8253]194    grok.context(ICustomStudentOnlinePayment)
[7976]195    grok.name('enterpin')
196    grok.template('enterpin')
[7929]197    grok.require('waeup.payStudent')
198
[7976]199    buttonname = _('Submit to eTranzact')
200    label = _('Requery eTranzact History')
201    action = 'query_history'
[7929]202
[8247]203class EtranzactEnterPinPageApplicant(EtranzactEnterPinPageStudent):
204    """
205    """
206    grok.require('waeup.payApplicant')
[8253]207    grok.context(ICustomApplicantOnlinePayment)
[8247]208
209class EtranzactQueryHistoryPageStudent(UtilityView, grok.View):
[7929]210    """ Query history of eTranzact payments
211    """
[8253]212    grok.context(ICustomStudentOnlinePayment)
[7929]213    grok.name('query_history')
214    grok.require('waeup.payStudent')
215
216    def update(self, confirmation_number=None):
[8430]217        ob_class = self.__implemented__.__name__
[7929]218        if self.context.p_state == 'paid':
219            self.flash(_('This ticket has already been paid.'))
220            return
221        student = self.context.getStudent()
[8430]222        success, msg, log = query_etranzact(confirmation_number,self.context)
223        student.loggerInfo(ob_class, log)
224        if not success:
225            self.flash(msg)
226            return
227        success, msg, log = self.context.doAfterStudentPayment()
228        if log is not None:
229            student.loggerInfo(ob_class, log)
230        self.flash(msg)
[8247]231        return
[7929]232
[8247]233    def render(self):
234        self.redirect(self.url(self.context, '@@index'))
235        return
[7929]236
[8247]237class EtranzactQueryHistoryPageApplicant(UtilityView, grok.View):
238    """ Query history of eTranzact payments
239    """
[8253]240    grok.context(ICustomApplicantOnlinePayment)
[8247]241    grok.name('query_history')
242    grok.require('waeup.payApplicant')
243
244    def update(self, confirmation_number=None):
[8430]245        ob_class = self.__implemented__.__name__
[8247]246        if self.context.p_state == 'paid':
247            self.flash(_('This ticket has already been paid.'))
[7929]248            return
[8247]249        applicant = self.context.__parent__
[8430]250        success, msg, log = query_etranzact(confirmation_number,self.context)
251        applicant.loggerInfo(ob_class, log)
252        if not success:
253            self.flash(msg)
254            return
255        success, msg, log = self.context.doAfterApplicantPayment()
256        if log is not None:
257            applicant.loggerInfo(ob_class, log)
258        self.flash(msg)
[7929]259        return
260
261    def render(self):
262        self.redirect(self.url(self.context, '@@index'))
[8259]263        return
Note: See TracBrowser for help on using the repository browser.