Changeset 7889


Ignore:
Timestamp:
15 Mar 2012, 21:53:34 (13 years ago)
Author:
Henrik Bettermann
Message:

First implementation of Interswitch callback validation (work in progress, see also email sent to Jason).

Location:
main/waeup.custom/trunk/src/waeup/custom/students
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.custom/trunk/src/waeup/custom/students/browser.py

    r7880 r7889  
    1616## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    1717##
     18from datetime import datetime
     19from urllib import urlencode
    1820import grok
    1921from zope.formlib.textwidgets import BytesDisplayWidget
     
    2123    FriendlyDateWidget, FriendlyDateDisplayWidget
    2224    )
    23 from waeup.kofa.browser.layout import KofaPage
     25from waeup.kofa.browser.layout import KofaPage, UtilityView
     26from waeup.kofa.accesscodes import create_accesscode
    2427from waeup.kofa.students.interfaces import IStudentOnlinePayment
    2528from waeup.kofa.students.browser import (
    2629    StudentPersonalDisplayFormPage, StudentPersonalManageFormPage,
    2730    StudentClearanceManageFormPage, StudentClearanceEditFormPage,
    28     StudentClearanceDisplayFormPage
    29     )
     31    StudentClearanceDisplayFormPage, write_log_message,
     32    OnlinePaymentDisplayFormPage)
    3033from waeup.kofa.students.viewlets import RequestCallbackActionButton
    3134from waeup.custom.students.interfaces import (
     
    6972    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
    7073
     74#class OnlinePaymentDisplayFormPage(OnlinePaymentDisplayFormPage):
     75#    """ Page to view an online payment ticket.
     76
     77#    The customized version provides also product data for
     78#    payment providers
     79#    """
     80
     81
    7182class InterswitchActionButton(RequestCallbackActionButton):
    7283    grok.order(2)
     
    7586    target = 'goto_interswitch'
    7687
     88    @property
     89    def target_url(self):
     90        if self.context.p_state != 'unpaid':
     91            return ''
     92        return self.view.url(self.view.context, self.target)
     93
    7794class RequestCallbackActionButton(RequestCallbackActionButton):
    7895    grok.order(3)
    7996    icon = 'actionicon_call.png'
    8097    text = _('Request CollegePAY callback')
    81     target = 'callback'
     98    product_id = '57'
     99   
     100    def target_url(self):
     101        if self.context.p_state != 'unpaid':
     102            return ''
     103        site_redirect_url = self.view.url(self.view.context, 'callback')
     104        query_url = "https://testwebpay.interswitchng.com/test_paydirect/services/TransactionQueryURL.aspx"
     105        args = {
     106            'transRef':self.context.p_id,
     107            'prodID':self.product_id,
     108            'redirectURL':site_redirect_url}
     109        return query_url + '?%s' % urlencode(args)
    82110
    83111class InterswitchPage(KofaPage):
     
    89117    grok.template('goto_interswitch')
    90118    grok.require('waeup.payStudent')
    91 
    92119    label = _('Submit data to CollegePAY (Interswitch Payment Gateway)')
    93120    submit_button = _('Submit')
    94 
    95     # Uniben product data (to be removed later)
    96     product_id = '57'
    97     currency = '566'
    98     pay_item_id = '5700'
    99 
    100121    action = 'https://testwebpay.interswitchng.com/test_paydirect/webpay/pay.aspx'
    101     site_redirect_url = 'http://localhost?echo='
    102122    site_name = 'xyz.waeup.org'
    103123    provider_acct = '2345'
     
    107127    institution_bank_id = '9'
    108128    institution_name = 'Sample University'
     129    currency = '566'
     130    pay_item_id = '5700'
     131    product_id = '57'
    109132
    110133    def update(self):
     
    119142        self.amount_100 = 100 * self.amount
    120143        self.local_date_time = str(self.context.creation_date)
     144        self.site_redirect_url = self.url(self.context, 'callback')
    121145        certificate = getattr(self.student['studycourse'],'certificate',None)
    122146        if certificate is not None:
     
    145169        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
    146170        return
     171
     172class OnlinePaymentCallbackPage(UtilityView, grok.View):
     173    """ Callback view for the CollegePAY gateway
     174    """
     175    grok.context(IStudentOnlinePayment)
     176    grok.name('callback')
     177    grok.require('waeup.payStudent')
     178
     179    # This view is not yet working for offline querying transactions
     180    # since the the query string differs from the query string sent after
     181    # posting transactions. This Interswitch bug must be removed first.
     182    # Alternatively, we could use the webservice only and replace
     183    # the RequestCallbackActionButton by a RequestWebserviceActionButton
     184
     185    def update(self):
     186        if self.context.p_state == 'paid':
     187            self.flash(_('This ticket has already been paid.'))
     188            return
     189        student = self.context.getStudent()
     190        query = self.request.form
     191        # Should be logged instead of printed
     192        print query
     193        if query.get('resp', None) != '00':
     194            self.flash(_('Unsuccessful callback: ${a}',
     195                mapping = {'a': query.get('desc', _('No query string'))}))
     196            write_log_message(self,'invalid callback: %s' % self.context.p_id)
     197            self.context.r_card_num = query.get('cardNum', None)
     198            self.context.r_code = query.get('resp', None)
     199            self.context.p_state = 'failed'
     200            return
     201
     202        # Add amount checking
     203
     204
     205        # Add webservice validation
     206
     207
     208        write_log_message(self,'valid callback: %s' % self.context.p_id)
     209        self.context.r_amount_approved = self.context.amount_auth
     210        self.context.r_card_num = query.get('cardNum', None)
     211        self.context.r_code = query.get('resp', None)
     212        self.context.r_desc = query.get('desc', None)
     213        self.context.r_pay_reference  = query.get('payRef', None)
     214        self.context.p_state = 'paid'
     215        self.context.payment_date = datetime.now()
     216
     217        if self.context.p_category == 'clearance':
     218            # Create CLR access code
     219            pin, error = create_accesscode('CLR',0,student.student_id)
     220            if error:
     221                self.flash(_('Valid callback received. ${a}',
     222                    mapping = {'a':error}))
     223                return
     224            self.context.ac = pin
     225        elif self.context.p_category == 'schoolfee':
     226            # Create SFE access code
     227            pin, error = create_accesscode('SFE',0,student.student_id)
     228            if error:
     229                self.flash(_('Valid callback received. ${a}',
     230                    mapping = {'a':error}))
     231                return
     232            self.context.ac = pin
     233        elif self.context.p_category == 'bed_allocation':
     234            # Create HOS access code
     235            pin, error = create_accesscode('HOS',0,student.student_id)
     236            if error:
     237                self.flash(_('Valid callback received. ${a}',
     238                    mapping = {'a':error}))
     239                return
     240            self.context.ac = pin
     241        self.flash(_('Valid callback received.'))
     242        return
     243
     244    def render(self):
     245        self.redirect(self.url(self.context, '@@index'))
     246        return
     247
     248
     249
  • main/waeup.custom/trunk/src/waeup/custom/students/tests.py

    r7886 r7889  
    9595    layer = FunctionalLayer
    9696
     97    def callback_url(self, payment_url, resp, apprAmt):
     98        return payment_url + (
     99            '/callback?echo=' +
     100            '&resp=%s' +
     101            '&desc=Something went wrong' +
     102            '&txnRef=p1331792385335' +
     103            '&payRef=' + '&retRef=' +
     104            '&cardNum=0' +
     105            '&apprAmt=%s' +
     106            '&url=http://xyz') % (resp, apprAmt)
     107
    97108    def test_manage_payments(self):
    98109        # Add missing configuration data
     
    130141
    131142        # Manager receives valid callback
    132         self.browser.open(payment_url)
    133         self.browser.getLink("Request CollegePAY callback").click()
     143        #self.browser.open(payment_url)
     144        #self.browser.getLink("Request CollegePAY callback").click()
     145
     146        self.browser.open(self.callback_url(payment_url, 'XX', '300'))
     147        self.assertMatches('...Unsuccessful callback: Something went wrong...',
     148                          self.browser.contents)
     149        self.assertMatches('...Failed...',
     150                           self.browser.contents)
     151        self.browser.open(self.payments_student_path + '/addop')
     152        self.browser.getControl("Create ticket").click()
     153        ctrl = self.browser.getControl(name='val_id')
     154
     155        #value = ctrl.options[1]
     156        #self.browser.getLink(value).click()
     157        #self.assertMatches('...Amount Authorized...',
     158        #                   self.browser.contents)
     159        #payment_url = self.browser.url
     160
     161        self.browser.open(payment_url + '/callback')
     162        self.assertMatches('...Unsuccessful callback: No query string...',
     163                          self.browser.contents)
     164        self.assertMatches('...Failed...',
     165                           self.browser.contents)
     166        #print self.browser.contents
     167        self.browser.open(self.callback_url(payment_url, '00', '300'))
    134168        self.assertMatches('...Valid callback received...',
    135169                          self.browser.contents)
    136 
    137170        self.browser.open(self.manage_student_path)
    138171        self.browser.getControl(
     
    147180                           self.browser.contents)
    148181        # Remove all payments so that we can add a school fee payment again
    149         for payment in self.student['payments'].keys():
     182        keys = [i for i in self.student['payments'].keys()]
     183        for payment in keys:
    150184            del self.student['payments'][payment]
    151185        self.browser.open(self.payments_student_path + '/addop')
Note: See TracChangeset for help on using the changeset viewer.