[IMP] payment_ogone: add support for s2s payments
This commit is contained in:
committed by
Christophe Simonis
parent
dbd3efef1f
commit
ef86cfaa1c
@@ -5,6 +5,7 @@ import werkzeug
|
||||
|
||||
from openerp import http, SUPERUSER_ID
|
||||
from openerp.http import request
|
||||
from openerp.addons.payment.models.payment_acquirer import ValidationError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -27,3 +28,30 @@ class OgoneController(http.Controller):
|
||||
cr, uid, context = request.cr, SUPERUSER_ID, request.context
|
||||
request.registry['payment.transaction'].form_feedback(cr, uid, post, 'ogone', context=context)
|
||||
return werkzeug.utils.redirect(post.pop('return_url', '/'))
|
||||
|
||||
@http.route(['/payment/ogone/s2s/create_json'], type='json', auth='public')
|
||||
def ogone_s2s_create_json(self, **kwargs):
|
||||
data = kwargs['params']
|
||||
acquirer_id = int(data.get('acquirer_id'))
|
||||
acquirer = request.env['payment.acquirer'].browse(acquirer_id)
|
||||
new_id = acquirer.s2s_process(data)
|
||||
return new_id
|
||||
|
||||
@http.route(['/payment/ogone/s2s/create'], type='http', auth='public')
|
||||
def ogone_s2s_create(self, **post):
|
||||
acquirer_id = int(post.get('acquirer_id'))
|
||||
acquirer = request.env['payment.acquirer'].browse(acquirer_id)
|
||||
acquirer.s2s_process(post)
|
||||
return werkzeug.utils.redirect(post.get('return_url', '/'))
|
||||
|
||||
@http.route(['/payment/ogone/s2s/feedback'])
|
||||
def feedback(self, **kwargs):
|
||||
cr, uid, context = request.cr, SUPERUSER_ID, request.context
|
||||
payment = request.registry.get('payment.transaction')
|
||||
try:
|
||||
tx = payment._ogone_form_get_tx_from_data(cr, uid, kwargs, context=context)
|
||||
payment._ogone_s2s_validate(tx)
|
||||
except ValidationError:
|
||||
return 'ko'
|
||||
|
||||
return 'ok'
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="payment_acquirer_ogone" model="payment.acquirer">
|
||||
<field name="name">Credit Card</field>
|
||||
<field name="name">Ogone</field>
|
||||
<field name="provider">ogone</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="ogone_acquirer_button"/>
|
||||
<field name="registration_view_template_id" ref="ogone_s2s_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
<p>You will be redirected to the Ogone website after clicking on the payment button.</p>]]></field>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-'8' "-*-"
|
||||
|
||||
import datetime
|
||||
from hashlib import sha1
|
||||
import logging
|
||||
from lxml import etree, objectify
|
||||
@@ -10,12 +11,14 @@ from urllib import urlencode
|
||||
import urllib2
|
||||
import urlparse
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.payment.models.payment_acquirer import ValidationError
|
||||
from openerp.addons.payment_ogone.controllers.main import OgoneController
|
||||
from openerp.addons.payment_ogone.data import ogone
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools import float_round
|
||||
from openerp.tools import float_round, DEFAULT_SERVER_DATE_FORMAT
|
||||
from openerp.tools.float_utils import float_compare
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -48,6 +51,10 @@ class PaymentAcquirerOgone(osv.Model):
|
||||
'ogone_password': fields.char('API User Password', required_if_provider='ogone'),
|
||||
'ogone_shakey_in': fields.char('SHA Key IN', size=32, required_if_provider='ogone'),
|
||||
'ogone_shakey_out': fields.char('SHA Key OUT', size=32, required_if_provider='ogone'),
|
||||
'ogone_alias_usage': fields.char('Alias Usage', help="""If you want to use Ogone Aliases,
|
||||
this default Alias Usage will be presented to
|
||||
the customer as the reason you want to
|
||||
keep his payment data""")
|
||||
}
|
||||
|
||||
def _ogone_generate_shasign(self, acquirer, inout, values):
|
||||
@@ -161,6 +168,11 @@ class PaymentAcquirerOgone(osv.Model):
|
||||
'EXCEPTIONURL': '%s' % urlparse.urljoin(base_url, OgoneController._exception_url),
|
||||
'CANCELURL': '%s' % urlparse.urljoin(base_url, OgoneController._cancel_url),
|
||||
}
|
||||
if tx_values.get('type') == 'form_save':
|
||||
temp_ogone_tx_values.update({
|
||||
'ALIAS': 'ODOO-NEW-ALIAS-%s' % time.time(), # something unique,
|
||||
'ALIASUSAGE': tx_values.get('alias_usage') or acquirer.ogone_alias_usage,
|
||||
})
|
||||
if ogone_tx_values.get('return_url'):
|
||||
temp_ogone_tx_values['PARAMPLUS'] = 'return_url=%s' % ogone_tx_values.pop('return_url')
|
||||
shasign = self._ogone_generate_shasign(acquirer, 'in', temp_ogone_tx_values)
|
||||
@@ -172,6 +184,31 @@ class PaymentAcquirerOgone(osv.Model):
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
return self._get_ogone_urls(cr, uid, acquirer.environment, context=context)['ogone_standard_order_url']
|
||||
|
||||
def ogone_s2s_form_validate(self, cr, uid, id, data, context=None):
|
||||
error = dict()
|
||||
error_message = []
|
||||
|
||||
mandatory_fields = ["cc_number", "cc_cvc", "cc_holder_name", "cc_expiry", "cc_brand"]
|
||||
# Validation
|
||||
for field_name in mandatory_fields:
|
||||
if not data.get(field_name):
|
||||
error[field_name] = 'missing'
|
||||
|
||||
return False if error else True
|
||||
|
||||
def ogone_s2s_form_process(self, cr, uid, data, context=None):
|
||||
values = {
|
||||
'cc_number': data.get('cc_number'),
|
||||
'cc_cvc': int(data.get('cc_cvc')),
|
||||
'cc_holder_name': data.get('cc_holder_name'),
|
||||
'cc_expiry': data.get('cc_expiry'),
|
||||
'cc_brand': data.get('cc_brand'),
|
||||
'acquirer_id': int(data.get('acquirer_id')),
|
||||
'partner_id': int(data.get('partner_id'))
|
||||
}
|
||||
pm_id = self.pool['payment.method'].create(cr, SUPERUSER_ID, values, context=context)
|
||||
return pm_id
|
||||
|
||||
|
||||
class PaymentTxOgone(osv.Model):
|
||||
_inherit = 'payment.transaction'
|
||||
@@ -181,21 +218,14 @@ class PaymentTxOgone(osv.Model):
|
||||
_ogone_pending_tx_status = [46] # 3DS HTML response
|
||||
_ogone_cancel_tx_status = [1]
|
||||
|
||||
_columns = {
|
||||
'ogone_3ds': fields.boolean('3DS Activated'),
|
||||
'ogone_3ds_html': fields.html('3DS HTML'),
|
||||
'ogone_complus': fields.char('Complus'),
|
||||
'ogone_payid': fields.char('PayID', help='Payment ID, generated by Ogone')
|
||||
}
|
||||
|
||||
# --------------------------------------------------
|
||||
# FORM RELATED METHODS
|
||||
# --------------------------------------------------
|
||||
|
||||
def _ogone_form_get_tx_from_data(self, cr, uid, data, context=None):
|
||||
""" Given a data dict coming from ogone, verify it and find the related
|
||||
transaction record. """
|
||||
reference, pay_id, shasign = data.get('orderID'), data.get('PAYID'), data.get('SHASIGN')
|
||||
transaction record. Create a payment method if an alias is returned."""
|
||||
reference, pay_id, shasign, alias = data.get('orderID'), data.get('PAYID'), data.get('SHASIGN'), data.get('ALIAS')
|
||||
if not reference or not pay_id or not shasign:
|
||||
error_msg = _('Ogone: received data with missing reference (%s) or pay_id (%s) or shashign (%s)') % (reference, pay_id, shasign)
|
||||
_logger.info(error_msg)
|
||||
@@ -220,6 +250,20 @@ class PaymentTxOgone(osv.Model):
|
||||
_logger.info(error_msg)
|
||||
raise ValidationError(error_msg)
|
||||
|
||||
# alias was created on ogone server, store it
|
||||
if alias:
|
||||
method_obj = self.pool['payment.method']
|
||||
domain = [('acquirer_ref', '=', alias)]
|
||||
cardholder = data.get('CN')
|
||||
if not method_obj.search_count(cr, uid, domain, context=context):
|
||||
_logger.info('Ogone: saving alias %s for partner %s' % (data.get('CARDNO'), tx.partner_id))
|
||||
ref = method_obj.create(cr, uid, {'name': data.get('CARDNO') + (' - ' + cardholder if cardholder else ''),
|
||||
'partner_id': tx.partner_id.id,
|
||||
'acquirer_id': tx.acquirer_id.id,
|
||||
'acquirer_ref': alias
|
||||
})
|
||||
tx.partner_reference = alias
|
||||
|
||||
return tx
|
||||
|
||||
def _ogone_form_get_invalid_parameters(self, cr, uid, tx, data, context=None):
|
||||
@@ -276,195 +320,189 @@ class PaymentTxOgone(osv.Model):
|
||||
# --------------------------------------------------
|
||||
# S2S RELATED METHODS
|
||||
# --------------------------------------------------
|
||||
|
||||
def ogone_s2s_create_alias(self, cr, uid, id, values, context=None):
|
||||
""" Create an alias at Ogone via batch.
|
||||
|
||||
.. versionadded:: pre-v8 saas-3
|
||||
.. warning::
|
||||
|
||||
Experimental code. You should not use it before OpenERP v8 official
|
||||
release.
|
||||
"""
|
||||
def ogone_s2s_do_transaction(self, cr, uid, id, context=None, **kwargs):
|
||||
# TODO: create tx with s2s type
|
||||
tx = self.browse(cr, uid, id, context=context)
|
||||
assert tx.type == 'server2server', 'Calling s2s dedicated method for a %s acquirer' % tx.type
|
||||
alias = 'OPENERP-%d-%d' % (tx.partner_id.id, tx.id)
|
||||
account = tx.acquirer_id
|
||||
reference = tx.reference or "ODOO-%s-%s" % (datetime.datetime.now().strftime('%y%m%d_%H%M%S'), tx.partner_id.id)
|
||||
|
||||
expiry_date = '%s%s' % (values['expiry_date_mm'], values['expiry_date_yy'][2:])
|
||||
line = 'ADDALIAS;%(alias)s;%(holder_name)s;%(number)s;%(expiry_date)s;%(brand)s;%(pspid)s'
|
||||
line = line % dict(values, alias=alias, expiry_date=expiry_date, pspid=tx.acquirer_id.ogone_pspid)
|
||||
|
||||
tx_data = {
|
||||
'FILE_REFERENCE': 'OPENERP-NEW-ALIAS-%s' % time.time(), # something unique,
|
||||
'TRANSACTION_CODE': 'ATR',
|
||||
'OPERATION': 'SAL',
|
||||
'NB_PAYMENTS': 1, # even if we do not actually have any payment, ogone want it to not be 0
|
||||
'FILE': line,
|
||||
'REPLY_TYPE': 'XML',
|
||||
'PSPID': tx.acquirer_id.ogone_pspid,
|
||||
'USERID': tx.acquirer_id.ogone_userid,
|
||||
'PSWD': tx.acquirer_id.ogone_password,
|
||||
'PROCESS_MODE': 'CHECKANDPROCESS',
|
||||
}
|
||||
|
||||
# TODO: fix URL computation
|
||||
request = urllib2.Request(tx.acquirer_id.ogone_afu_agree_url, urlencode(tx_data))
|
||||
result = urllib2.urlopen(request).read()
|
||||
|
||||
try:
|
||||
tree = objectify.fromstring(result)
|
||||
except etree.XMLSyntaxError:
|
||||
_logger.exception('Invalid xml response from ogone')
|
||||
return None
|
||||
|
||||
error_code = error_str = None
|
||||
if hasattr(tree, 'PARAMS_ERROR'):
|
||||
error_code = tree.NCERROR.text
|
||||
error_str = 'PARAMS ERROR: %s' % (tree.PARAMS_ERROR.text or '',)
|
||||
else:
|
||||
node = tree.FORMAT_CHECK
|
||||
error_node = getattr(node, 'FORMAT_CHECK_ERROR', None)
|
||||
if error_node is not None:
|
||||
error_code = error_node.NCERROR.text
|
||||
error_str = 'CHECK ERROR: %s' % (error_node.ERROR.text or '',)
|
||||
|
||||
if error_code:
|
||||
error_msg = ogone.OGONE_ERROR_MAP.get(error_code)
|
||||
error = '%s\n\n%s: %s' % (error_str, error_code, error_msg)
|
||||
_logger.info(error)
|
||||
raise Exception(error) # TODO specific exception
|
||||
|
||||
tx.write({'partner_reference': alias})
|
||||
return True
|
||||
|
||||
def ogone_s2s_generate_values(self, cr, uid, id, custom_values, context=None):
|
||||
""" Generate valid Ogone values for a s2s tx.
|
||||
|
||||
.. versionadded:: pre-v8 saas-3
|
||||
.. warning::
|
||||
|
||||
Experimental code. You should not use it before OpenERP v8 official
|
||||
release.
|
||||
"""
|
||||
tx = self.browse(cr, uid, id, context=context)
|
||||
tx_data = {
|
||||
'PSPID': tx.acquirer_id.ogone_pspid,
|
||||
'USERID': tx.acquirer_id.ogone_userid,
|
||||
'PSWD': tx.acquirer_id.ogone_password,
|
||||
'OrderID': tx.reference,
|
||||
'amount': '%d' % int(float_round(tx.amount, 2) * 100), # tde check amount or str * 100 ?
|
||||
data = {
|
||||
'PSPID': account.ogone_pspid,
|
||||
'USERID': account.ogone_userid,
|
||||
'PSWD': account.ogone_password,
|
||||
'ORDERID': reference,
|
||||
'AMOUNT': long(tx.amount * 100),
|
||||
'CURRENCY': tx.currency_id.name,
|
||||
'LANGUAGE': tx.partner_lang,
|
||||
'OPERATION': 'SAL',
|
||||
'ECI': 2, # Recurring (from MOTO)
|
||||
'ALIAS': tx.partner_reference,
|
||||
'RTIMEOUT': 30,
|
||||
}
|
||||
if custom_values.get('ogone_cvc'):
|
||||
tx_data['CVC'] = custom_values.get('ogone_cvc')
|
||||
if custom_values.pop('ogone_3ds', None):
|
||||
tx_data.update({
|
||||
'FLAG3D': 'Y', # YEAH!!
|
||||
|
||||
if kwargs.get('3d_secure'):
|
||||
data.update({
|
||||
'FLAG3D': 'Y',
|
||||
'LANGUAGE': tx.partner_id.lang or 'en_US',
|
||||
})
|
||||
if custom_values.get('ogone_complus'):
|
||||
tx_data['COMPLUS'] = custom_values.get('ogone_complus')
|
||||
if custom_values.get('ogone_accept_url'):
|
||||
pass
|
||||
|
||||
shasign = self.pool['payment.acquirer']._ogone_generate_shasign(tx.acquirer_id, 'in', tx_data)
|
||||
tx_data['SHASIGN'] = shasign
|
||||
return tx_data
|
||||
for url in 'accept decline exception'.split():
|
||||
key = '{0}_url'.format(url)
|
||||
val = kwargs.pop(key, None)
|
||||
if val:
|
||||
key = '{0}URL'.format(url).upper()
|
||||
data[key] = val
|
||||
|
||||
def ogone_s2s_feedback(self, cr, uid, data, context=None):
|
||||
"""
|
||||
.. versionadded:: pre-v8 saas-3
|
||||
.. warning::
|
||||
data['SHASIGN'] = self.pool['payment.acquirer']._ogone_generate_shasign(tx.acquirer_id, 'in', data)
|
||||
|
||||
Experimental code. You should not use it before OpenERP v8 official
|
||||
release.
|
||||
"""
|
||||
pass
|
||||
direct_order_url = 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % (tx.acquirer_id.environment)
|
||||
|
||||
def ogone_s2s_execute(self, cr, uid, id, values, context=None):
|
||||
"""
|
||||
.. versionadded:: pre-v8 saas-3
|
||||
.. warning::
|
||||
|
||||
Experimental code. You should not use it before OpenERP v8 official
|
||||
release.
|
||||
"""
|
||||
tx = self.browse(cr, uid, id, context=context)
|
||||
|
||||
tx_data = self.ogone_s2s_generate_values(cr, uid, id, values, context=context)
|
||||
_logger.info('Generated Ogone s2s data %s', pformat(tx_data)) # debug
|
||||
|
||||
request = urllib2.Request(tx.acquirer_id.ogone_direct_order_url, urlencode(tx_data))
|
||||
_logger.debug("Ogone data %s", pformat(data))
|
||||
request = urllib2.Request(direct_order_url, urlencode(data))
|
||||
result = urllib2.urlopen(request).read()
|
||||
_logger.info('Contacted Ogone direct order; result %s', result) # debug
|
||||
_logger.debug('Ogone response = %s', result)
|
||||
|
||||
tree = objectify.fromstring(result)
|
||||
payid = tree.get('PAYID')
|
||||
try:
|
||||
tree = objectify.fromstring(result)
|
||||
except etree.XMLSyntaxError:
|
||||
# invalid response from ogone
|
||||
_logger.exception('Invalid xml response from ogone')
|
||||
raise
|
||||
|
||||
query_direct_data = dict(
|
||||
PSPID=tx.acquirer_id.ogone_pspid,
|
||||
USERID=tx.acquirer_id.ogone_userid,
|
||||
PSWD=tx.acquirer_id.ogone_password,
|
||||
ID=payid,
|
||||
)
|
||||
query_direct_url = 'https://secure.ogone.com/ncol/%s/querydirect.asp' % (tx.acquirer_id.environment,)
|
||||
return self._ogone_s2s_validate_tree(tx, tree)
|
||||
|
||||
def _ogone_s2s_validate(self, tx):
|
||||
tree = self._ogone_s2s_get_tx_status(tx)
|
||||
return self.ogone_s2s_validate(tx, tree)
|
||||
|
||||
def _ogone_s2s_validate_tree(self, tx, tree, tries=2):
|
||||
if tx.state not in ('draft', 'pending'):
|
||||
return True # already validated
|
||||
|
||||
status = int(tree.get('STATUS', '0'))
|
||||
if status in self._ogone_valid_tx_status:
|
||||
tx.write({
|
||||
'state': 'done',
|
||||
'date_validate': datetime.date.today().strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
'acquirer_reference': tree.get('PAYID'),
|
||||
})
|
||||
if tx.s2s_cb_eval:
|
||||
safe_eval(tx.s2s_cb_eval, {'self': tx})
|
||||
return True
|
||||
elif status in self._ogone_cancel_tx_status:
|
||||
tx.write({
|
||||
'state': 'cancel',
|
||||
'acquirer_reference': tree.get('PAYID'),
|
||||
})
|
||||
elif status in self._ogone_pending_tx_status:
|
||||
tx.write({
|
||||
'state': 'pending',
|
||||
'acquirer_reference': tree.get('PAYID'),
|
||||
'html_3ds': str(tree.HTML_ANSWER).decode('base64')
|
||||
})
|
||||
elif status in self._ogone_wait_tx_status and tries > 0:
|
||||
time.sleep(1500)
|
||||
tx.write({'acquirer_reference': tree.get('PAYID')})
|
||||
tree = self._ogone_s2s_get_tx_status(tx)
|
||||
return self.ogone_s2s_validate(tx, tree, tries - 1)
|
||||
else:
|
||||
error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % {
|
||||
'error_str': tree.get('NCERROR'),
|
||||
'error_code': tree.get('NCERRORPLUS'),
|
||||
'error_msg': ogone.OGONE_ERROR_MAP.get(tree.get('NCERRORPLUS')),
|
||||
}
|
||||
_logger.info(error)
|
||||
tx.write({
|
||||
'state': 'error',
|
||||
'state_message': error,
|
||||
'acquirer_reference': tree.get('PAYID'),
|
||||
})
|
||||
return False
|
||||
|
||||
def _ogone_s2s_get_tx_status(self, tx):
|
||||
account = tx.acquirer_id
|
||||
#reference = tx.reference or "ODOO-%s-%s" % (datetime.datetime.now().strftime('%Y%m%d_%H%M%S'), tx.partner_id.id)
|
||||
|
||||
data = {
|
||||
'PAYID': tx.acquirer_reference,
|
||||
'PSPID': account.ogone_pspid,
|
||||
'USERID': account.ogone_userid,
|
||||
'PSWD': account.ogone_password,
|
||||
}
|
||||
|
||||
query_direct_url = 'https://secure.ogone.com/ncol/%s/querydirect.asp' % (tx.acquirer_id.environment)
|
||||
|
||||
_logger.debug("Ogone data %s", pformat(data))
|
||||
request = urllib2.Request(query_direct_url, urlencode(data))
|
||||
result = urllib2.urlopen(request).read()
|
||||
_logger.debug('Ogone response = %s', result)
|
||||
|
||||
try:
|
||||
tree = objectify.fromstring(result)
|
||||
except etree.XMLSyntaxError:
|
||||
# invalid response from ogone
|
||||
_logger.exception('Invalid xml response from ogone')
|
||||
raise
|
||||
|
||||
return tree
|
||||
|
||||
|
||||
class PaymentMethod(osv.Model):
|
||||
_inherit = 'payment.method'
|
||||
|
||||
def ogone_create(self, cr, uid, values, context=None):
|
||||
if values.get('cc_number'):
|
||||
# create a alias via batch
|
||||
values['cc_number'] = values['cc_number'].replace(' ', '')
|
||||
acquirer = self.pool['payment.acquirer'].browse(cr, uid, values['acquirer_id'])
|
||||
alias = 'ODOO-NEW-ALIAS-%s' % time.time()
|
||||
|
||||
expiry = str(values['cc_expiry'][:2]) + str(values['cc_expiry'][-2:])
|
||||
line = 'ADDALIAS;%(alias)s;%(cc_holder_name)s;%(cc_number)s;%(expiry)s;%(cc_brand)s;%(pspid)s'
|
||||
line = line % dict(values, alias=alias, expiry=expiry, pspid=acquirer.ogone_pspid)
|
||||
|
||||
data = {
|
||||
'FILE_REFERENCE': alias,
|
||||
'TRANSACTION_CODE': 'ATR',
|
||||
'OPERATION': 'SAL',
|
||||
'NB_PAYMENTS': 1, # even if we do not actually have any payment, ogone want it to not be 0
|
||||
'FILE': line,
|
||||
'REPLY_TYPE': 'XML',
|
||||
'PSPID': acquirer.ogone_pspid,
|
||||
'USERID': acquirer.ogone_userid,
|
||||
'PSWD': acquirer.ogone_password,
|
||||
'PROCESS_MODE': 'CHECKANDPROCESS',
|
||||
}
|
||||
|
||||
url = 'https://secure.ogone.com/ncol/%s/AFU_agree.asp' % (acquirer.environment,)
|
||||
request = urllib2.Request(url, urlencode(data))
|
||||
|
||||
result = urllib2.urlopen(request).read()
|
||||
|
||||
tries = 2
|
||||
tx_done = False
|
||||
tx_status = False
|
||||
while not tx_done or tries > 0:
|
||||
try:
|
||||
tree = objectify.fromstring(result)
|
||||
except etree.XMLSyntaxError:
|
||||
# invalid response from ogone
|
||||
_logger.exception('Invalid xml response from ogone')
|
||||
raise
|
||||
return None
|
||||
|
||||
# see https://secure.ogone.com/ncol/paymentinfos1.asp
|
||||
VALID_TX = [5, 9]
|
||||
WAIT_TX = [41, 50, 51, 52, 55, 56, 91, 92, 99]
|
||||
PENDING_TX = [46] # 3DS HTML response
|
||||
# other status are errors...
|
||||
|
||||
status = tree.get('STATUS')
|
||||
if status == '':
|
||||
status = None
|
||||
error_code = error_str = None
|
||||
if hasattr(tree, 'PARAMS_ERROR'):
|
||||
error_code = tree.NCERROR.text
|
||||
error_str = 'PARAMS ERROR: %s' % (tree.PARAMS_ERROR.text or '',)
|
||||
else:
|
||||
status = int(status)
|
||||
node = tree.FORMAT_CHECK
|
||||
error_node = getattr(node, 'FORMAT_CHECK_ERROR', None)
|
||||
if error_node is not None:
|
||||
error_code = error_node.NCERROR.text
|
||||
error_str = 'CHECK ERROR: %s' % (error_node.ERROR.text or '',)
|
||||
|
||||
if status in VALID_TX:
|
||||
tx_status = True
|
||||
tx_done = True
|
||||
if error_code:
|
||||
error_msg = tree.get(error_code)
|
||||
error = '%s\n\n%s: %s' % (error_str, error_code, error_msg)
|
||||
_logger.error(error)
|
||||
raise Exception(error)
|
||||
|
||||
elif status in PENDING_TX:
|
||||
html = str(tree.HTML_ANSWER)
|
||||
tx_data.update(ogone_3ds_html=html.decode('base64'))
|
||||
tx_status = False
|
||||
tx_done = True
|
||||
|
||||
elif status in WAIT_TX:
|
||||
time.sleep(1500)
|
||||
|
||||
request = urllib2.Request(query_direct_url, urlencode(query_direct_data))
|
||||
result = urllib2.urlopen(request).read()
|
||||
_logger.debug('Contacted Ogone query direct; result %s', result)
|
||||
|
||||
else:
|
||||
error_code = tree.get('NCERROR')
|
||||
if not ogone.retryable(error_code):
|
||||
error_str = tree.get('NCERRORPLUS')
|
||||
error_msg = ogone.OGONE_ERROR_MAP.get(error_code)
|
||||
error = 'ERROR: %s\n\n%s: %s' % (error_str, error_code, error_msg)
|
||||
_logger.info(error)
|
||||
raise Exception(error)
|
||||
|
||||
tries = tries - 1
|
||||
|
||||
if not tx_done and tries == 0:
|
||||
raise Exception('Cannot get transaction status...')
|
||||
|
||||
return tx_status
|
||||
return {
|
||||
'acquirer_ref': alias,
|
||||
'name': 'XXXXXXXXXXXX%s - %s' % (values['cc_number'][-4:], values['cc_holder_name'])
|
||||
}
|
||||
return {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<data>
|
||||
|
||||
<template id="ogone_acquirer_button">
|
||||
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
|
||||
@@ -19,6 +19,10 @@
|
||||
<input type='hidden' name='OWNERCTY' t-att-value='tx_values["OWNERCTY"]'/>
|
||||
<input type='hidden' name='OWNERTOWN' t-att-value='tx_values["OWNERTOWN"]'/>
|
||||
<input type='hidden' name='OWNERTELNO' t-att-value='tx_values["OWNERTELNO"]'/>
|
||||
<t t-if="type == 'form_save'">
|
||||
<input type='hidden' name='ALIAS' t-att-value='tx_values["ALIAS"]'/>
|
||||
<input type='hidden' name='ALIASUSAGE' t-att-value='tx_values["ALIASUSAGE"]'/>
|
||||
</t>
|
||||
<!-- before payment verification -->
|
||||
<input type='hidden' name='SHASIGN' t-att-value='tx_values["SHASIGN"]'/>
|
||||
<!-- look and print -->
|
||||
@@ -49,5 +53,39 @@
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template id="ogone_s2s_form">
|
||||
<form method="post" t-att-action="'/payment/ogone/s2s/create' if not json else '/payment/ogone/s2s/create_json'">
|
||||
<div t-att-class="'row' if bootstrap_formatting else ''">
|
||||
<div t-att-class="'form-group col-md-8' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cc_number">Card number</label>
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="•••• •••• •••• •••• "/>
|
||||
<div class="card_placeholder"></div>
|
||||
<div class="visa"></div>
|
||||
<input type="hidden" name="cc_brand" value=""/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cc_cvc">CVC</label>
|
||||
<input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-7' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cc_holder_name">Name</label>
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cc_expires_mm">Expires</label>
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="MM / YY"/>
|
||||
</div>
|
||||
<input type="hidden" name="acquirer_id" t-att-value="id"/>
|
||||
<input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
|
||||
<input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
|
||||
<div class="clearfix"/>
|
||||
</div>
|
||||
<button t-att-class="submit_class" class="btn btn-primary" type="submit">
|
||||
<span t-if="not submit_txt">Confirm <span class="fa fa-long-arrow-right"></span></span>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -14,29 +14,11 @@
|
||||
<field name="ogone_password"/>
|
||||
<field name="ogone_shakey_in"/>
|
||||
<field name="ogone_shakey_out"/>
|
||||
<field name="ogone_alias_usage"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="transaction_form_ogone" model="ir.ui.view">
|
||||
<field name="name">acquirer.transaction.form.ogone</field>
|
||||
<field name="model">payment.transaction</field>
|
||||
<field name="inherit_id" ref="payment.transaction_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//notebook' position='inside'>
|
||||
<page string="Ogone TX Details">
|
||||
<group>
|
||||
<field name="ogone_payid"/>
|
||||
<field name="ogone_3ds"/>
|
||||
<field name="ogone_3ds_html"/>
|
||||
<field name="ogone_complus"/>
|
||||
<field name="ogone_payid"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
Reference in New Issue
Block a user