Ignore:
Timestamp:
24 Apr 2012, 15:37:51 (13 years ago)
Author:
Henrik Bettermann
Message:

Remove surcharge configuration completely.

Implement application fee and school fee payments via Interswitch (part 3)

Location:
main/waeup.uniben/trunk/src/waeup/uniben/interswitch
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.uniben/trunk/src/waeup/uniben/interswitch/browser.py

    r8259 r8263  
    2323from waeup.kofa.browser.layout import KofaPage, UtilityView
    2424from waeup.kofa.accesscodes import create_accesscode
    25 from waeup.uniben.students.interfaces import ICustomStudentOnlinePayment
    26 from waeup.uniben.applicants.interfaces import ICustomApplicantOnlinePayment
     25from waeup.kofa.interfaces import RETURNING
    2726from waeup.kofa.students.browser import write_log_message
    2827from waeup.kofa.students.viewlets import RequestCallbackActionButton as RCABStudent
    2928from waeup.kofa.applicants.viewlets import RequestCallbackActionButton as RCABApplicant
    3029from waeup.kofa.payments.interfaces import payment_categories
     30from waeup.uniben.students.interfaces import ICustomStudentOnlinePayment
     31from waeup.uniben.applicants.interfaces import ICustomApplicantOnlinePayment
    3132from waeup.uniben.students.utils import actions_after_student_payment
    3233from waeup.uniben.applicants.utils import actions_after_applicant_payment
     
    5253
    5354PRODUCT_ID = '57'
    54 SITE_NAME = 'xyz.waeup.org'
    55 PROVIDER_ACCT = '2345'
    56 PROVIDER_BANK_ID = '8'
    57 PROVIDER_ITEM_NAME = 'Kofa Provider Fee'
    58 INSTITUTION_ACCT = '1234'
    59 INSTITUTION_BANK_ID = '9'
    60 INSTITUTION_NAME = 'Sample University'
     55SITE_NAME = 'uniben-kofa.waeup.org'
     56PROVIDER_ACCT = '0061001000021095'
     57PROVIDER_BANK_ID = '89'
     58PROVIDER_ITEM_NAME = 'BT Education'
     59INSTITUTION_NAME = 'Uniben'
    6160CURRENCY = '566'
    62 PAY_ITEM_ID = '5700'
    63 QUERY_URL =   'https://testwebpay.interswitchng.com/test_paydirect/services/TransactionQueryURL.aspx'
     61#QUERY_URL = 'https://webpay.interswitchng.com/paydirect/services/TransactionQueryURL.aspx'
     62QUERY_URL = 'https://testwebpay.interswitchng.com/test_paydirect/services/TransactionQueryURL.aspx'
     63#POST_ACTION = 'https://webpay.interswitchng.com/paydirect/webpay/pay.aspx'
    6464POST_ACTION = 'https://testwebpay.interswitchng.com/test_paydirect/webpay/pay.aspx'
    6565
     66#HOST = 'webpay.interswitchng.com'
    6667HOST = 'testwebpay.interswitchng.com'
     68#URL = '/paydirect/services/TransactionQueryWs.asmx'
    6769URL = '/test_paydirect/services/TransactionQueryWs.asmx'
    6870httplib.HTTPConnection.debuglevel = 0
    6971
    70 
    71 def collect_xml_data(payment, xmldict):
    72     xmldict['detail_ref'] = payment.p_id
    73     xmldict['provider_amt'] = 100 * payment.surcharge_1
    74     xmldict['provider_acct'] = PROVIDER_ACCT
    75     xmldict['provider_bank_id'] = PROVIDER_BANK_ID
    76     xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
    77     xmldict['institution_amt'] = 100 * payment.amount_auth
    78     xmldict['institution_acct'] = INSTITUTION_ACCT
    79     xmldict['institution_bank_id'] = INSTITUTION_BANK_ID
    80     xmldict['institution_item_name'] = payment.p_category
    81     xmldict['institution_name'] = INSTITUTION_NAME
    82     # Interswitch amount is not part of the xml data
    83     xmltext = """<payment_item_detail>
    84 <item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
    85 <item_detail item_id="1" item_name="%(institution_item_name)s" item_amt="%(institution_amt)d" bank_id="%(institution_bank_id)s" acct_num="%(institution_acct)s" />
    86 <item_detail item_id="2" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
    87 </item_details>
    88 </payment_item_detail>""" % xmldict
    89     xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
    90     return xml_data
    9172
    9273def SOAP_post(soap_action,xml):
     
    146127        payment.p_state = 'failed'
    147128        return False
    148     total_amount_auth = (
    149         payment.amount_auth
    150         + payment.surcharge_1
    151         + payment.surcharge_2)
    152     if payment.r_amount_approved != total_amount_auth:
     129    if payment.r_amount_approved != payment.amount_auth:
    153130        view.flash(_('Wrong amount'))
    154131        user.loggerInfo(ob_class,'successful callback but wrong amount: %s'
     
    167144    return True
    168145
    169 
    170146class InterswitchActionButtonStudent(RCABStudent):
    171147    grok.order(1)
     
    240216    site_name = SITE_NAME
    241217    currency = CURRENCY
    242     pay_item_id = PAY_ITEM_ID
     218    pay_item_id = '5700'
    243219    product_id = PRODUCT_ID
    244220
     
    250226            return
    251227
    252         self.student = self.context.getStudent()
     228        student = self.student = self.context.getStudent()
    253229        certificate = getattr(self.student['studycourse'],'certificate',None)
    254230        xmldict = {}
     
    259235            xmldict['department'] = None
    260236            xmldict['faculty'] = None
    261         self.amount = (self.context.amount_auth + self.context.surcharge_1 +
    262             self.context.surcharge_2 + self.context.surcharge_3)
     237        self.amount_special = 100 * (self.context.amount_auth - 150)
    263238        self.category = payment_categories.getTermByToken(
    264239            self.context.p_category).title
    265         self.amount_100 = 100 * self.amount
    266240        self.local_date_time = str(self.context.creation_date)
    267241        self.site_redirect_url = self.url(self.context, 'request_webservice')
    268         self.xml_data = collect_xml_data(self.context, xmldict)
    269         return
    270 
    271 class InterswitchPageApplicant(InterswitchPageStudent):
     242        # Provider data
     243        xmldict['detail_ref'] = self.context.p_id
     244        xmldict['provider_acct'] = PROVIDER_ACCT
     245        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
     246        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
     247        if student.current_mode.endswith('_ft') \
     248            and student.state == RETURNING:
     249            provider_amt = 600
     250        else:
     251            provider_amt = 1500
     252        xmldict['provider_amt'] = 100 * provider_amt
     253        # Institution data
     254        studycourse = student['studycourse']
     255        xmldict['institution_acct'] = ''
     256        xmldict['institution_bank_id'] = ''
     257        if student.current_mode.endswith('_ft'):
     258            #post-grad full-time students of all faculties
     259            if studycourse.current_level in ('700','710','800','810','900','910'):
     260                xmldict['institution_acct'] = '1012842833'
     261                xmldict['institution_bank_id'] = '117'
     262            #all other part-time students depending on faculty
     263            elif student.faccode in ('SSC','LAW','MED'):
     264                xmldict['institution_acct'] = '0005986938'
     265                xmldict['institution_bank_id'] = '31'
     266            elif student.faccode in ('ENG','PSC','PHA'):
     267                xmldict['institution_acct'] = '0014413973'
     268                xmldict['institution_bank_id'] = '129'
     269            elif student.faccode in ('LSC','DEN','AGR'):
     270                xmldict['institution_acct'] = '1012801319'
     271                xmldict['institution_bank_id'] = '117'
     272            elif student.faccode in ('ART','EDU','MGS','BMS'):
     273                xmldict['institution_acct'] = '6220027556'
     274                xmldict['institution_bank_id'] = '51'
     275        elif student.current_mode.endswith('_pt'):
     276            #post-grad part-time students of all faculties
     277            if studycourse.current_level in ('700','710','800','810','900','910'):
     278                xmldict['institution_acct'] = '0023708207'
     279                xmldict['institution_bank_id'] = '72'
     280            #all other part-time students depending on faculty
     281            elif student.faccode in ('ENG','LAW','MGS'):
     282                xmldict['institution_acct'] = '2019006824'
     283                xmldict['institution_bank_id'] = '8'
     284            elif student.faccode in ('IPA','PHA','SSC','AGR','EDU'):
     285                xmldict['institution_acct'] = '0122012109'
     286                xmldict['institution_bank_id'] = '16'
     287        xmldict['institution_amt'] = self.amount_special - 100 * provider_amt
     288        xmldict['institution_item_name'] = self.context.p_category
     289        xmldict['institution_name'] = INSTITUTION_NAME
     290        # Interswitch amount is not part of the xml data
     291        xmltext = """<payment_item_detail>
     292<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s" department="%(department)s" faculty="%(faculty)s">
     293<item_detail item_id="1" item_name="%(institution_item_name)s" item_amt="%(institution_amt)d" bank_id="%(institution_bank_id)s" acct_num="%(institution_acct)s" />
     294<item_detail item_id="2" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
     295</item_details>
     296</payment_item_detail>""" % xmldict
     297        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
     298        return
     299
     300class InterswitchPageApplicant(KofaPage):
    272301    """ View which sends a POST request to the Interswitch
    273302    CollegePAY payment gateway.
     
    276305    grok.require('waeup.payApplicant')
    277306    grok.template('applicant_goto_interswitch')
     307    grok.name('goto_interswitch')
     308    label = _('Submit data to CollegePAY (Interswitch Payment Gateway)')
     309    submit_button = _('Submit')
     310    action = POST_ACTION
     311    site_name = SITE_NAME
     312    currency = CURRENCY
     313    pay_item_id = '5700'
     314    product_id = PRODUCT_ID
    278315
    279316    def update(self):
    280         #if self.context.p_state != 'unpaid':
    281         #    self.flash(_("Payment ticket can't be re-send to CollegePAY."))
    282         #    self.redirect(self.url(self.context, '@@index'))
    283         #    return
     317        if self.context.p_state != 'unpaid':
     318            self.flash(_("Payment ticket can't be re-send to CollegePAY."))
     319            self.redirect(self.url(self.context, '@@index'))
     320            return
    284321        self.applicant = self.context.__parent__
    285322        xmldict = {}
    286         xmldict['department'] = None
    287         xmldict['faculty'] = None
    288323        self.category = payment_categories.getTermByToken(
    289324            self.context.p_category).title
    290         self.amount = (self.context.amount_auth + self.context.surcharge_1 +
    291             self.context.surcharge_2 + self.context.surcharge_3)
    292         self.amount_100 = 100 * self.amount
     325        # substract invisible Interswitch surcharge
     326        self.amount_special = 100 * (self.context.amount_auth - 150)
    293327        self.local_date_time = str(self.context.creation_date)
    294328        self.site_redirect_url = self.url(self.context, 'request_webservice')
    295         self.xml_data = collect_xml_data(self.context, xmldict)
     329        # Provider data
     330        xmldict['detail_ref'] = self.context.p_id
     331        xmldict['provider_amt'] = 100 * 400
     332        xmldict['provider_acct'] = PROVIDER_ACCT
     333        xmldict['provider_bank_id'] = PROVIDER_BANK_ID
     334        xmldict['provider_item_name'] = PROVIDER_ITEM_NAME
     335        # Institution data
     336        xmldict['institution_amt'] = 100 * (self.context.amount_auth - 400 - 150)
     337        xmldict['institution_acct'] = '123456'
     338        xmldict['institution_bank_id'] = '99'
     339        xmldict['institution_item_name'] = self.context.p_category
     340        xmldict['institution_name'] = INSTITUTION_NAME
     341        # Interswitch amount is not part of the xml data
     342        xmltext = """<payment_item_detail>
     343<item_details detail_ref="%(detail_ref)s" college="%(institution_name)s">
     344<item_detail item_id="1" item_name="%(institution_item_name)s" item_amt="%(institution_amt)d" bank_id="%(institution_bank_id)s" acct_num="%(institution_acct)s" />
     345<item_detail item_id="2" item_name="%(provider_item_name)s" item_amt="%(provider_amt)d" bank_id="%(provider_bank_id)s" acct_num="%(provider_acct)s" />
     346</item_details>
     347</payment_item_detail>""" % xmldict
     348        self.xml_data = """<input type="hidden" name="xml_data" value='%s'  />""" % xmltext
    296349        return
    297350
    298351# Deprecated
    299 class InterswitchPaymentCallbackPageStudent(UtilityView, grok.View):
    300     """ Callback view for the CollegePAY gateway
    301     """
    302     grok.context(ICustomStudentOnlinePayment)
    303     grok.name('isw_callback')
    304     grok.require('waeup.payStudent')
     352#class InterswitchPaymentCallbackPageStudent(UtilityView, grok.View):
     353#    """ Callback view for the CollegePAY gateway
     354#    """
     355#    grok.context(ICustomStudentOnlinePayment)
     356#    grok.name('isw_callback')
     357#    grok.require('waeup.payStudent')
    305358
    306359    # This view is not yet working for offline querying transactions
     
    310363    # the RequestCallbackActionButton by a RequestWebserviceActionButton
    311364
    312     def update(self):
    313         if self.context.p_state == 'paid':
    314             self.flash(_('This ticket has already been paid.'))
    315             return
    316         student = self.context.getStudent()
    317         query = self.request.form
    318         write_log_message(self,'callback received: %s' % query)
    319 
    320         self.context.r_card_num = query.get('cardNum', None)
    321         self.context.r_code = query.get('resp', None)
    322         self.context.r_pay_reference  = query.get('payRef', None)
    323         self.context.r_amount_approved = float(query.get('apprAmt', '0.0')) / 100
    324         self.context.r_desc = query.get('desc', None)
    325 
    326         if self.context.r_code != '00':
    327             self.flash(_('Unsuccessful callback: ${a}',
    328                 mapping = {'a': query.get('desc', _('Incomplete query string.'))}))
    329             write_log_message(self,'unsuccessful callback: %s' % self.context.p_id)
    330             self.context.p_state = 'failed'
    331             return
    332 
    333         total_amount_auth = (
    334             self.context.amount_auth
    335             + self.context.surcharge_1
    336             + self.context.surcharge_2)
    337 
    338         if self.context.r_amount_approved != total_amount_auth:
    339             self.flash(_('Wrong amount'))
    340             write_log_message(
    341                 self,'successful but wrong amount: %s' % self.context.p_id)
    342             self.context.p_state = 'failed'
    343             return
    344 
    345         try:
    346             validation_list = get_SOAP_response(
    347                 PRODUCT_ID, self.context.p_id).split(':')
     365#    def update(self):
     366#        if self.context.p_state == 'paid':
     367#            self.flash(_('This ticket has already been paid.'))
     368#            return
     369#        student = self.context.getStudent()
     370#        query = self.request.form
     371#        write_log_message(self,'callback received: %s' % query)
     372#        self.context.r_card_num = query.get('cardNum', None)
     373#        self.context.r_code = query.get('resp', None)
     374#        self.context.r_pay_reference  = query.get('payRef', None)
     375#        self.context.r_amount_approved = float(query.get('apprAmt', '0.0')) / 100
     376#        self.context.r_desc = query.get('desc', None)
     377#        if self.context.r_code != '00':
     378#            self.flash(_('Unsuccessful callback: ${a}',
     379#                mapping = {'a': query.get('desc', _('Incomplete query string.'))}))
     380#            write_log_message(self,'unsuccessful callback: %s' % self.context.p_id)
     381#            self.context.p_state = 'failed'
     382#            return
     383#        if self.context.r_amount_approved != payment.amount_auth:
     384#            self.flash(_('Wrong amount'))
     385#            write_log_message(
     386#                self,'successful but wrong amount: %s' % self.context.p_id)
     387#            self.context.p_state = 'failed'
     388#            return
     389#        try:
     390#            validation_list = get_SOAP_response(
     391#                PRODUCT_ID, self.context.p_id).split(':')
    348392            # Validation does not make sense yet since the query string
    349393            # formats are conflicting. We are only printing the validation
    350394            # string, nothing else.
    351             print 'WARNING: Webservice validation is not yet implemented'
    352             print 'validation list: %s' % validation_list
    353         except:
    354             print 'Connection to webservice failed.'
    355 
     395#            print 'WARNING: Webservice validation is not yet implemented'
     396#            print 'validation list: %s' % validation_list
     397#        except:
     398#            print 'Connection to webservice failed.'
    356399        # Add webservice validation here
    357 
    358         write_log_message(self,'valid callback: %s' % self.context.p_id)
    359         self.context.p_state = 'paid'
    360         self.context.payment_date = datetime.now()
    361         actions_after_student_payment(student, self.context, self)
    362         return
    363 
    364     def render(self):
    365         self.redirect(self.url(self.context, '@@index'))
    366         return
     400#        write_log_message(self,'valid callback: %s' % self.context.p_id)
     401#        self.context.p_state = 'paid'
     402#        self.context.payment_date = datetime.now()
     403#        actions_after_student_payment(student, self.context, self)
     404#        return
     405
     406#    def render(self):
     407#        self.redirect(self.url(self.context, '@@index'))
     408#        return
    367409
    368410# Alternative solution, replaces InterswitchPaymentCallbackPage
  • main/waeup.uniben/trunk/src/waeup/uniben/interswitch/browser_templates/applicant_goto_interswitch.pt

    r8259 r8263  
    1515          Total Amount Authorized:</td>
    1616        <td>
    17           <span tal:replace="view/amount">AMOUNT</span>
     17          <span tal:replace="view/context/amount_auth">AMOUNT</span>
    1818        </td>
    1919      </tr>
     
    6262  <input type="hidden" name="site_name" tal:attributes="value view/site_name" />
    6363  <input type="hidden" name="local_date_time" tal:attributes="value view/local_date_time" />
    64   <input type="hidden" name="amount" tal:attributes="value view/amount_100" />
     64  <input type="hidden" name="amount" tal:attributes="value view/amount_special" />
    6565  <input type="hidden" name="txn_ref" tal:attributes="value view/context/p_id" />
    6666  <input type="hidden" name="pay_item_name" tal:attributes="value view/context/p_item" />
  • main/waeup.uniben/trunk/src/waeup/uniben/interswitch/browser_templates/student_goto_interswitch.pt

    r8259 r8263  
    1515          Total Amount Authorized:</td>
    1616        <td>
    17           <span tal:replace="view/amount">AMOUNT</span>
     17          <span tal:replace="view/context/amount_auth">AMOUNT</span>
    1818        </td>
    1919      </tr>
     
    6262  <input type="hidden" name="site_name" tal:attributes="value view/site_name" />
    6363  <input type="hidden" name="local_date_time" tal:attributes="value view/local_date_time" />
    64   <input type="hidden" name="amount" tal:attributes="value view/amount_100" />
     64  <input type="hidden" name="amount" tal:attributes="value view/amount_special" />
    6565  <input type="hidden" name="txn_ref" tal:attributes="value view/context/p_id" />
    6666  <input type="hidden" name="pay_item_name" tal:attributes="value view/context/p_item" />
  • main/waeup.uniben/trunk/src/waeup/uniben/interswitch/tests.py

    r8256 r8263  
    5959
    6060
    61     def callback_url(self, payment_url, resp, apprAmt):
    62         return payment_url + (
    63             '/isw_callback?echo=' +
    64             '&resp=%s' +
    65             '&desc=Something went wrong' +
    66             '&txnRef=p1331792385335' +
    67             '&payRef=' + '&retRef=' +
    68             '&cardNum=0' +
    69             '&apprAmt=%s' +
    70             '&url=http://xyz') % (resp, apprAmt)
     61#    def callback_url(self, payment_url, resp, apprAmt):
     62#        return payment_url + (
     63#            '/isw_callback?echo=' +
     64#            '&resp=%s' +
     65#            '&desc=Something went wrong' +
     66#            '&txnRef=p1331792385335' +
     67#            '&payRef=' + '&retRef=' +
     68#            '&cardNum=0' +
     69#            '&apprAmt=%s' +
     70#            '&url=http://xyz') % (resp, apprAmt)
    7171
    7272    def test_interswitch_form(self):
     
    7777                           self.browser.contents)
    7878        self.assertMatches(
    79             '...<input type="hidden" name="amount" value="4000000.0" />...',
     79            '...<input type="hidden" name="amount" value="3985000.0" />...',
    8080            self.browser.contents)
    8181
    82     @external_test
    83     def test_callback(self):
     82#    @external_test
     83#    def test_callback(self):
    8484
    8585        # Manager can call callback manually
    86         self.browser.open(self.callback_url(self.payment_url, 'XX', '300'))
    87         self.assertMatches('...Unsuccessful callback: Something went wrong...',
    88                           self.browser.contents)
    89         self.assertMatches('...Failed...',
    90                            self.browser.contents)
    91         self.browser.open(self.payment_url + '/isw_callback')
    92         self.assertMatches('...Unsuccessful callback: Incomplete query string...',
    93                           self.browser.contents)
    94         self.assertMatches('...Failed...',
    95                            self.browser.contents)
    96         self.browser.open(self.callback_url(self.payment_url, '00', '300000'))
    97         self.assertMatches('...Wrong amount...',
    98                           self.browser.contents)
    99         self.browser.open(self.callback_url(self.payment_url, '00', '4000000'))
    100         self.assertMatches('...Valid callback received...',
    101                           self.browser.contents)
     86#        self.browser.open(self.callback_url(self.payment_url, 'XX', '300'))
     87#        self.assertMatches('...Unsuccessful callback: Something went wrong...',
     88#                          self.browser.contents)
     89#        self.assertMatches('...Failed...',
     90#                           self.browser.contents)
     91#        self.browser.open(self.payment_url + '/isw_callback')
     92#        self.assertMatches('...Unsuccessful callback: Incomplete query string...',
     93#                          self.browser.contents)
     94#        self.assertMatches('...Failed...',
     95#                           self.browser.contents)
     96#        self.browser.open(self.callback_url(self.payment_url, '00', '300000'))
     97#        self.assertMatches('...Wrong amount...',
     98#                          self.browser.contents)
     99#        self.browser.open(self.callback_url(self.payment_url, '00', '4000000'))
     100#        self.assertMatches('...Valid callback received...',
     101#                          self.browser.contents)
    102102
    103103    @external_test
Note: See TracChangeset for help on using the changeset viewer.