[IMP] payment_acquirer: continuing base model.

Two main models : payment.acquirer and payment.transaction.

payment.acquirer models the acquirer: paypal, ogone. Each specific
acquirer will inherit from the class and add specific fields.

payment.transaction models the transaction itself. It has basic fields
for a transaction: date, partner, partner fields (to hold data at
transaction time), reference, state and its message, amount, currency.

Class methods are not finished and still quite WIP.

payment.acqurier has a render method that is used to render
its form. The form is the 'pay now' button with the specific
sementic of each acquirer.

This model is supposed to work on form-based and server-to-server
implementation methods.

bzr revid: tde@openerp.com-20131107171558-jrwrj3ll9kol6bav
This commit is contained in:
Thibault Delavallée 2013-11-07 18:15:58 +01:00
parent 420cdb13a2
commit 3d0ac6643e
7 changed files with 415 additions and 429 deletions

View File

@ -26,10 +26,14 @@
'version': '0.1',
'description': """Payment acquirer module, use to display payment method and validate the payments.""",
'author': 'OpenERP SA',
'depends': ['decimal_precision'],
'depends': ['decimal_precision', 'mail'],
'data': [
'views/acquirer_view.xml',
'views/payment_acquirer_views.xml',
'views/ogone.xml',
'views/paypal.xml',
'data/payment_acquirer_data.xml',
'data/ogone.xml',
'data/paypal.xml',
'security/ir.model.access.csv',
],
'installable': True,

View File

@ -21,12 +21,76 @@
from openerp.addons.web import http
from openerp.addons.web.http import request
# from openerp.addons.payment_acquirer.models.payment_acquirer import ValidationError
from openerp.addons.website.models import website
import logging
import requests
from urllib import urlencode
class website_project(http.Controller):
_logger = logging.getLogger(__name__)
@website.route(['/payment_acquirer/<path:acquirer>/'], type='http', auth="public")
def project(self, acquirer=None, **post):
obj = request.registry['payment.acquirer']
return obj.transaction_feedback(request.cr, request.uid, acquirer, context=request.context, **post)
class PaypalController(http.Controller):
_notify_url = '/payment/paypal/ipn/'
_return_url = '/payment/paypal/dpn/'
_cancel_url = '/payment/paypal/cancel/'
# _ipn_url2 = '/payment/paypal/<int:acquirer_id>/ipn/'
@website.route('/payment/paypal/<int:acquirer_id>/ipn/', type='http', auth='admin')
def paypal_ipn(self, **post):
print 'Entering paypal_ipn with post', post
# step 1: return an empty HTTP 200 response -> will be done at the end by returning ''
# step 2: POST the complete, unaltered message back to Paypal (preceded by cmd=_notify-validate), with same encoding
paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
post_url = '%s?cmd=_notify-validate&%s' % (paypal_url, urlencode(post))
resp = requests.post(post_url)
print '\tReceived response', resp, resp.text
# step 3: paypal send either VERIFIED or INVALID (single word)
if resp.text == 'VERIFIED':
# _logger.warning('')
cr, uid, context = request.cr, request.uid, request.context
# payment_transaction = request.registry['payment.transaction']
# payment_transaction.validate()
elif resp.text == 'INVALID':
# _logger.warning('')
pass
else:
# _logger.warning('') -> something went wrong
pass
return ''
@website.route([
'/payment/paypal/test/dpn',
], type='http', auth="public")
def paypal_test_success(self, **post):
""" TODO
"""
cr, uid, context = request.cr, request.uid, request.context
print post
return ''
class OgoneController(http.Controller):
_accept_url = '/payment/ogone/test/accept'
_decline_url = '/payment/ogone/test/decline'
_exception_url = '/payment/ogone/test/exception'
_cancel_url = '/payment/ogone/test/cancel'
@website.route([
'/payment/ogone/feedback', '/payment/ogone/test/accept',
'/payment/ogone/decline', '/payment/ogone/test/decline',
'/payment/ogone/exception', '/payment/ogone/test/exception',
'/payment/ogone/cancel', '/payment/ogone/test/cancel',
], type='http', auth='admin')
def feedback(self, **post):
cr, uid, context = request.cr, request.uid, request.context
Payment = request.registry['payment.transaction']
print 'Entering ogone feedback with', post
res = Payment.tx_ogone_feedback(cr, uid, post, context)
print res
return ''

View File

@ -3,7 +3,7 @@
<data noupdate="0">
<!-- Paypal -->
<!--
<template id="paypal_acquirer_view">
<form t-if="object.company_id.paypal_account" action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post" target="_self">
<input type="hidden" name="cmd" value="_xclick"/>
@ -16,17 +16,36 @@
<input t-if="cancel_url" type="hidden" name="cancel_url" t-att-value="cancel_url"/>
<input type="image" name="submit" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
</form>
</template>
</template> -->
<record id="paypal_acquirer" model="payment.acquirer">
<!-- <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="alfred@gmail.com">
<input type="hidden" name="lc" value="US">
<input type="hidden" name="item_name" value="object_name">
<input type="hidden" name="item_number" value="object_id">
<input type="hidden" name="amount" value="23.00">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="button_subtype" value="services">
<input type="hidden" name="no_note" value="0">
<input type="hidden" name="tax_rate" value="21.000">
<input type="hidden" name="shipping" value="2.00">
<input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynowCC_LG.gif:NonHostedGuest">
<input type="image" src="https://www.paypalobjects.com/fr_XC/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - la solution de paiement en ligne la plus simple et la plus sécurisée !">
<img alt="" border="0" src="https://www.paypalobjects.com/fr_XC/i/scr/pixel.gif" width="1" height="1">
</form> -->
<!-- <record id="paypal_acquirer" model="payment.acquirer">
<field name="acquirer">paypal</field>
<field name="form_template_id" ref="paypal_acquirer_view"/>
<field name="type_id" ref="paypal"/>
</record>
</record> -->
<!-- Virement -->
<template id="virement_acquirer_view">
<!-- <template id="virement_acquirer_view">
<div>
<table>
<tr><td>Numero de compte: </td><td></td></tr>
@ -40,6 +59,6 @@
<field name="acquirer">virement</field>
<field name="form_template_id" ref="virement_acquirer_view"/>
<field name="type_id" ref="virement"/>
</record>
</record> -->
</data>
</openerp>

View File

@ -20,3 +20,5 @@
##############################################################################
import payment_acquirer
import paypal
import ogone

View File

@ -19,399 +19,223 @@
#
##############################################################################
import openerp
from openerp.addons.payment_acquirer.models import ogone_errors
from openerp.osv import osv, fields
from openerp.tools import float_repr
from openerp.tools.safe_eval import safe_eval
from hashlib import sha1
from lxml import etree, objectify
import logging
from pprint import pformat
import requests
import urlparse
import time
from urllib import urlencode
import urllib2
_logger = logging.getLogger(__name__)
def _generate_ogone_shasign(acc, inout, values):
assert inout in ('in', 'out')
assert acc.provider == 'ogone'
key = acc['ogone_shakey_' + inout]
def filter_key(key):
if inout == 'in':
return True
else:
keys = "ORDERID CURRENCY AMOUNT PM ACCEPTANCE STATUS CARDNO ALIAS ED CN TRXDATE PAYID NCERROR BRAND ECI IP COMPLUS".split()
return key.upper() in keys
items = sorted((k.upper(), v) for k, v in values.items())
sign = ''.join('%s=%s%s' % (k, v, key) for k, v in items if v and filter_key(k))
shasign = sha1(sign).hexdigest()
return shasign
class ValidationError(ValueError):
pass
class Payment(osv.Model):
class PaymentAcquirer(osv.Model):
_name = 'payment.acquirer'
_description = 'Online Payment Acquirer'
_columns = {
'name': fields.char('Name', required=True),
'view_template_id': fields.many2one('ir.ui.view', required=True),
'env': fields.selection(
[('test', 'Test'), ('prod', 'Production')],
string='Environment'),
'portal_published': fields.boolean('Visible in Portal',
help="Make this payment acquirer available (Customer invoices, etc.)"),
}
_defaults = {
'portal_published': True,
'env': 'test',
}
def _check_required_if_provider(self, cr, uid, ids, context=None):
for acquirer in self.browse(cr, uid, ids, context=context):
if any(c for c, f in self._all_columns.items() if getattr(f.column, 'required_if_provider', None) == acquirer.name and not acquirer[c]):
return False
return True
_constraints = [
(_check_required_if_provider, 'Required fields not filled', ['required for this provider']),
]
def render(self, cr, uid, id, reference, amount, currency, tx_id=None, partner_id=False, partner_values=None, tx_custom_values=None, context=None):
""" Renders the form template of the given acquirer as a qWeb template.
All templates should handle:
- acquirer: the payment.acquirer browse record
- user: the current user browse record
- currency: currency browse record
- amount: amount of the transaction
- reference: reference of the transaction
- partner: the current partner browse record, if any (not necessarily set)
- partner_values: a dictionary of partner-related values
- tx_values: a dictionary of transaction related values that depends on
on the acquirer
- context: OpenERP context dictionary
:param string reference: the transaction reference
:param float amount: the amount the buyer has to pay
:param res.currency browse record currency: currency
:param int tx_id: id of a transaction; if set, bypasses all other given
values and only render the already-stored transaction
:param res.partner browse record partner_id: the buyer
:param dict partner_values: a dictionary of values for the buyer (see above)
:param dict tx_custom_values: a dictionary of values for the transction
that is given to the acquirer-specific method
generating the form values
:param dict context: OpenERP context
"""
if context is None:
context = {}
partner = None
if partner_id:
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
acquirer = self.browse(cr, uid, id, context=context)
method_name = '%s_form_generate_values' % (acquirer.name)
tx_values = {}
if tx_id and hasattr(self.pool['payment.transaction'], method_name):
method = getattr(self.pool['payment.transaction'], method_name)
tx_values = method(cr, uid, tx_id, tx_custom_values, context=context)
elif hasattr(self, method_name):
method = getattr(self, method_name)
tx_values = method(cr, uid, id, reference, amount, currency, partner_id, partner_values, tx_custom_values, context=context)
qweb_context = {
'acquirer': acquirer,
'user': self.pool.get("res.users").browse(cr, uid, uid, context=context),
'reference': reference,
'amount': amount,
'currency': currency,
'partner': partner,
'partner_values': partner_values,
'tx_values': tx_values,
'context': context,
}
return self.pool['ir.ui.view'].render(cr, uid, acquirer.view_template_id.id, qweb_context, engine='ir.qweb', context=context)
class PaymentTransaction(osv.Model):
_name = 'payment.transaction'
_inherit = ['mail.thread']
_order = 'id desc'
_columns = {
'create_date': fields.datetime('Creation Date', readonly=True, required=True),
'partner_id': fields.related('creditcard_id', 'partner_id', type='many2one', relation='res.partner', readonly=True),
'amount': fields.integer('Amount', required=True, help='in cents'),
'date_create': fields.datetime('Creation Date', readonly=True, required=True),
'date_validate': fields.datetime('Validation Date'),
'acquirer_id': fields.many2one(
'payment.acquirer', 'Acquirer',
required=True,
),
'type': fields.selection(
[('server2server', 'Server To Server'), ('form', 'Form')],
string='Type', required=True),
'state': fields.selection(
[('draft', 'Draft'), ('pending', 'Pending'),
('done', 'Done'), ('error', 'Error')],
'Status', required=True,
track_visiblity='onchange'),
'state_message': fields.text('Message',
help='Field used to store error and/or validation messages for information'),
# payment
'amount': fields.float('Amount', required=True,
help='Amount in cents',
track_visibility='always'),
'currency_id': fields.many2one('res.currency', 'Currency', required=True),
'reference': fields.char('Order Reference'),
'acquirer_ref': fields.char('Payment Acquirer Ref'),
'state': fields.selection([("pending", "Pending"), ("validated", "Validated"), ("refused", "Refused")], 'Status', required=True),
'res_model': fields.char('Object Model'),
'res_id': fields.char('Object Id'),
'reference': fields.char('Order Reference', required=True),
'name': fields.char('Item name'),
# duplicate partner / transaction data to store the values at transaction time
'partner_id': fields.many2one('res.partner', 'Partner'),
'partner_name': fields.char('Partner Name'),
'partner_lang': fields.char('Lang'),
'partner_email': fields.char('Email'),
'partner_zip': fields.char('Zip'),
'partner_address': fields.char('Address'),
'partner_city': fields.char('City'),
'partner_country_id': fields.many2one('res.country', 'Country'),
'partner_phone': fields.char('Phone'),
'partner_reference': fields.char('Buyer Reference'),
}
class acquirer(osv.Model):
_name = 'payment.acquirer'
_description = 'Online Payment Acquirer'
def list_acquirers(self, cr, uid, context=None):
return [("virement", "Virement")]
_columns = {
'name': fields.char('Name', required=True),
'acquirer': fields.selection(lambda self, *a, **k: self.list_acquirers(*a, **k), 'Acquirer', required=True),
'form_template_id': fields.many2one('ir.ui.view', required=True),
'visible': fields.boolean('Visible', help="Make this payment acquirer available (Customer invoices, etc.)"),
}
def _check_required_if_acquirer(self, cr, uid, ids, context=None):
for this in self.browse(cr, uid, ids, context=context):
if any(c for c, f in self._all_columns.items() if getattr(f.column, 'required_if_acquirer', None) == this.acquirer and not this[c]):
return False
return True
_constraints = [
(_check_required_if_acquirer, 'Required fields not filled', ['required for this payment acquirer']),
]
_defaults = {
'visible': True,
'date_create': fields.datetime.now,
'type': 'form',
'state': 'draft',
'partner_lang': 'en_US',
}
def render(self, cr, uid, id, object, reference, currency, amount, cancel_url=None, return_url=None, context=None):
""" Renders the form template of the given acquirer as a qWeb template """
user = self.pool.get("res.users")
precision = self.pool.get("decimal.precision").precision_get(cr, openerp.SUPERUSER_ID, 'Account')
def create(self, cr, uid, values, context=None):
if not 'name' in values and 'reference' in values:
values['name'] = values['reference']
if values.get('partner_id'):
values.update(self.on_change_partner_id(cr, uid, None, values.get('partner_id'), context=context)['values'])
if not context:
context = {}
if values.get('acquirer_id'):
acquirer = self.pool['payment.acquirer'].browse(cr, uid, values.get('acquirer_id'), context=context)
custom_method_name = '%s_create' % acquirer.name
if hasattr(self, custom_method_name):
values.update(getattr(self, custom_method_name)(cr, uid, values, context=context))
if isinstance(id, list):
id = id[0]
return super(PaymentTransaction, self).create(cr, uid, values, context=context)
qweb_context = {}
qweb_context.update(
object=object,
reference=reference,
currency=currency,
amount=amount,
amount_str=float_repr(amount, precision),
user_id=user.browse(cr, uid, uid),
context=context,
cancel_url=cancel_url,
return_url=return_url
)
def on_change_partner_id(self, cr, uid, ids, partner_id, context=None):
if partner_id:
partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context)
values = {
'partner_name': partner.name,
'partner_lang': partner.lang,
'partner_email': partner.email,
'partner_zip': partner.zip,
'partner_address': ' '.join((partner.street, partner.street2)).strip(),
'partner_city': partner.city,
'partner_country_id': partner.country_id.id,
'partner_phone': partner.phone,
}
else:
values = {
'partner_name': False,
'partner_lang': 'en_US',
'partner_email': False,
'partner_zip': False,
'partner_address': False,
'partner_city': False,
'partner_country_id': False,
'partner_phone': False,
}
return {'values': values}
return self.browse(cr, uid, id, context=context) \
.form_template_id.render(qweb_context, engine='ir.qweb', context=context) \
.strip()
def validate_payement(self, cr, uid, id, object, reference, currency, amount, context=None):
def validate(self, cr, uid, ids, context=None):
"""
return (status, retry_time, log)
status: "validated" or "refused" or "pending"
retry_time = False (don't retry validation) or int (seconds for retry validation)
log = str
"""
res = []
for tx in self.browse(cr, uid, ids, context=context):
method = getattr(self, '%s_validate')
status, retry_time, log = method(cr, uid, [tx.id], context=context)[0]
if isinstance(id, list):
id = id[0]
pay = self.browse(cr, uid, id, context=context)
method = getattr(self, '_validate_payement_%s' % pay.acquirer)
status, retry_time, log = method(object, reference, currency, amount, context=context)
# log transaction and payment
if getattr(object, 'message_post'):
object.message_post(
cr, uid, False,
# log validation on transaction
self.message_post(
cr, uid, tx.id,
body=log or "",
subject="%s%s" % (status, retry_time and ": %s" % retry_time or ""),
type='notification',
context=context
)
if status == "validated":
_logger.info("Payment Validate for %s:%s" % (object._name, reference))
elif status == "pending":
_logger.debug("Payment Pending for %s:%s. Reason: %s" % (object._name, reference, log))
else:
_logger.error("Payment Refused for %s:%s. Reason: %s" % (object._name, reference, log))
return (status, retry_time, log)
def _validate_payement_virement(self, object, reference, currency, amount, context=None):
return ("pending", False, "")
def transaction_feedback(self, cr, uid, acquirer, context=None, **values):
method = getattr(self, '_transaction_feedback_%s' % acquirer)
return method(**values)
# paypal
class acquirer_paypal(osv.osv):
_inherit = 'payment.acquirer'
def list_acquirers(self, cr, uid, context=None):
l = super(acquirer_paypal, self).list_acquirers(cr, uid, context)
l.append(('paypal', 'Paypal'))
return l
def _validate_payement_paypal(self, object, reference, currency, amount, context=None):
parameters = {}
parameters.update(
cmd='_notify-validate',
business=object.company_id.paypal_account,
item_name="%s %s" % (object.company_id.name, reference),
item_number=reference,
amount=amount,
currency_code=currency.name
)
paypal_url = "https://www.paypal.com/cgi-bin/webscr"
paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
response = urlparse.parse_qsl(requests.post(paypal_url, data=parameters))
# transaction's unique id
# response["txn_id"]
# "Failed", "Reversed", "Refunded", "Canceled_Reversal", "Denied"
status = "refused"
retry_time = False
if response["payment_status"] == "Voided":
status = "refused"
elif response["payment_status"] in ("Completed", "Processed") and response["item_number"] == reference and response["mc_gross"] == amount:
status = "validated"
elif response["payment_status"] in ("Expired", "Pending"):
status = "pending"
retry_time = 60
return (status, retry_time, "payment_status=%s&pending_reason=%s&reason_code=%s" % (
response["payment_status"],
response.get("pending_reason"),
response.get("reason_code")))
def _transaction_feedback_paypal(self, **values):
print values
return True
# ogone
class acquirer_ogone(osv.Model):
_name = 'payment.payment'
_columns = {
'ogone_3ds': fields.dummy('3ds activated'),
'ogone_3ds_html': fields.text(),
'ogone_feedback_model': fields.char(),
'ogone_feedback_eval': fields.char(),
# just for info
'ogone_accepturl': fields.dummy(),
'ogone_declineurl': fields.dummy(),
'ogone_exceptionurl': fields.dummy(),
'ogone_complus': fields.dummy(),
}
def _create_ogone(self, cr, uid, creditcard, values):
currency = self.pool['res.currency'].browse(cr, uid, values['currency_id'])
orderid = values.get('order_ref') or 'OE-ORDER-%s' % (time.time(),)
account = creditcard.provider_account_id
_logger.debug("Values %s", pformat(values))
data = {
'PSPID': account.ogone_pspid,
'USERID': account.ogone_userid,
'PSWD': account.ogone_password,
'OrderID': orderid,
'amount': values['amount'],
'CURRENCY': currency.name,
'OPERATION': 'SAL',
'ECI': 2, # Recurring (from MOTO)
'ALIAS': creditcard.provider_ref,
'RTIMEOUT': 30,
}
if creditcard.cvc:
data['CVC'] = creditcard.cvc
if values.pop('ogone_3ds', None):
data.update({
'FLAG3D': 'Y', # YEAH!!
'LANGUAGE': creditcard.partner_id.lang or 'en_US',
})
complus = values.get('ogone_complus')
if complus:
data['COMPLUS'] = complus
for url in 'accept decline exception'.split():
key = 'ogone_{0}url'.format(url)
val = values.pop(key, None)
if val:
key = '{0}URL'.format(url).upper()
data[key] = val
_logger.debug("data %s", pformat(data))
data['SHASIGN'] = _generate_ogone_shasign(account, 'in', data)
direct_order_url = 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % (account.ogone_env,)
request = urllib2.Request(direct_order_url, urlencode(data))
result = urllib2.urlopen(request).read()
_logger.debug('result = %s', result)
try:
tree = objectify.fromstring(result)
except etree.XMLSyntaxError:
# invalid response from ogone
_logger.exception('Invalid xml response from ogone')
raise
payid = tree.get('PAYID')
query_direct_data = dict(
PSPID=account.ogone_pspid,
USERID=account.ogone_userid,
PSWD=account.ogone_password,
ID=payid,
)
query_direct_url = 'https://secure.ogone.com/ncol/%s/querydirect.asp' % (account.ogone_env,)
def check_status(tree, tries=2):
# 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
if status == "validated":
_logger.info("Tx Validated for %s:%s" % (tx.acquirer_id.name, tx.reference))
elif status == "pending":
_logger.debug("Tx Pending for %s:%s. Reason: %s" % (tx.acquirer_id.name, tx.reference))
else:
status = int(status)
_logger.error("Tx Refused for %s:%s. Reason: %s" % (tx.acquirer_id.name, tx.reference))
if status in VALID_TX:
return True, (orderid, payid)
res.append((status, retry_time, log))
if status in PENDING_TX:
html = str(tree.HTML_ANSWER)
values.update(ogone_3ds_html=html.decode('base64'))
return False, (orderid, payid)
return res
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('result = %s', result)
try:
tree = objectify.fromstring(result)
except etree.XMLSyntaxError:
# invalid response from ogone
pass # retry...
if tries == 0:
raise Exception('Cannot get transaction status...')
return check_status(tree, tries - 1)
else:
error_code = tree.get('NCERROR')
if tries and ogone_errors.retryable(error_code):
return check_status(tree, tries - 1)
error_str = tree.get('NCERRORPLUS')
error_msg = ogone_errors.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)
return check_status(tree)
def _ogone_3ds_action(self, cr, uid, ids, context=None):
assert len(ids) == 1
p = self.browse(cr, uid, ids[0], context=context)
return {
'type': 'ir.actions.client',
'tag': 'ogone_3ds',
'params': {
'payment_id': p.id,
}
}
def _check_sha_sign_out(self, cr, uid, data, context=None):
"""Verify the SHA OUT signature of a ogone request.
return the linked payment (which must be in pending mode)
"""
payid = data['PAYID']
orderid = data['orderID']
p_ids = self.search(cr, uid, [('provider_ref', '=', payid), ('order_ref', '=', orderid)], context=context)
if len(p_ids) != 1:
raise ValidationError('Unknow order')
payment = self.browse(cr, uid, p_ids[0], context=context)
# if payment.state != 'pending':
# raise ValidationError('Invalid order')
shasign = data['SHASIGN'].upper()
if shasign != _generate_ogone_shasign(payment.creditcard_id.provider_account_id, 'out', data).upper():
raise ValidationError('SHASIGN validation error')
return payment
def _ogone_transaction_feedback(self, cr, uid, data, context=None):
payment = self._check_sha_sign_out(cr, uid, data, context)
status = int(data.get('STATUS') or '0')
if status in [5, 9]:
payment.write(dict(state='done'))
if payment.ogone_feedback_model and payment.ogone_feedback_eval:
model = self.pool.get(payment.ogone_feedback_model)
if model:
locals_ = {'cr': cr, 'uid': uid, 'model': model}
safe_eval(payment.ogone_feedback_eval, locals_)
return True
else:
error_code = data.get('NCERROR')
error_str = data.get('NCERRORPLUS')
error_msg = ogone_errors.OGONE_ERROR_MAP.get(error_code)
error = 'ERROR: %s\n\n%s: %s' % (error_str, error_code, error_msg)
_logger.info(error)
payment.write({'state': 'error', 'error': error})
return False
def create_s2s(self, cr, uid, context=None):
pass

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="acquirer_form" model="ir.ui.view">
<field name="model">payment.acquirer</field>
<field name="arch" type="xml">
<form string="Payment Acquirer" version="7.0">
<group col="1">
<div class="oe_title">
<label for="name" class="oe_edit_only"/><h1><field name="name"/></h1>
<div class="oe_edit_only"><field name="visible"/><label for="visible"/></div>
</div>
<group string="Form Template">
<div>
<p>
This is an HTML form template to submit a payment through this acquirer.
The template will be rendered with qWeb, so it may use qWeb expressions.
The qWeb evaluation context provides:
<ul>
<li>reference: the reference number of the document to pay</li>
<li>currency: the currency record in which the document is issued (e.g. currency.name could be EUR)</li>
<li>amount: the total amount to pay, as a float</li>
<li>amount_str: the total amount to pay, as a string with the account precision</li>
<li>object: the browse record on which the payment form is rendered (usually an invoice or sales order record)</li>
<li>user_id: the current user browse record</li>
<li>context: the current context dictionary</li>
</ul>
If the template renders to an empty result in a certain context it will be ignored, as if it was inactive.
</p>
</div>
<field name="form_template" nolabel="1" colspan="2"/>
</group>
</group>
</form>
</field>
</record>
<record id="acquirer_list" model="ir.ui.view">
<field name="model">payment.acquirer</field>
<field name="arch" type="xml">
<tree string="Payment Acquirers">
<field name="name"/>
<field name="visible"/>
</tree>
</field>
</record>
<record id="acquirer_search" model="ir.ui.view">
<field name="model">payment.acquirer</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
</search>
</field>
</record>
<!-- Acquirers list action is visible in Invoicing Settings -->
<record model="ir.actions.act_window" id="action_acquirer_list">
<field name="name">Payment Acquirers</field>
<field name="res_model">payment.acquirer</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<menuitem
name='Payments'
id='root_payment_menu'
parent='base.menu_administration'/>
<record id="acquirer_form" model="ir.ui.view">
<field name="model">payment.acquirer</field>
<field name="arch" type="xml">
<form string="Payment Acquirer" version="7.0">
<group col="1">
<div class="oe_title">
<label for="name" class="oe_edit_only"/><h1><field name="name"/></h1>
<div class="oe_edit_only"><field name="portal_published"/><label for="portal_published"/></div>
<field name="env"/>
</div>
<group string="Form Template">
<div>
<p>
This is an HTML form template to submit a payment through this acquirer.
The template will be rendered with qWeb, so it may use qWeb expressions.
The qWeb evaluation context provides:
<ul>
<li>reference: the reference number of the document to pay</li>
<li>currency: the currency record in which the document is issued (e.g. currency.name could be EUR)</li>
<li>amount: the total amount to pay, as a float</li>
<li>amount_str: the total amount to pay, as a string with the account precision</li>
<li>object: the browse record on which the payment form is rendered (usually an invoice or sales order record)</li>
<li>user_id: the current user browse record</li>
<li>context: the current context dictionary</li>
</ul>
If the template renders to an empty result in a certain context it will be ignored, as if it was inactive.
</p>
</div>
<field name="view_template_id" nolabel="1" colspan="2"/>
</group>
</group>
</form>
</field>
</record>
<record id="acquirer_list" model="ir.ui.view">
<field name="model">payment.acquirer</field>
<field name="arch" type="xml">
<tree string="Payment Acquirers">
<field name="name"/>
<field name="portal_published"/>
<field name="env"/>
</tree>
</field>
</record>
<record id="acquirer_search" model="ir.ui.view">
<field name="model">payment.acquirer</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_payment_acquirer">
<field name="name">Payment Acquirers</field>
<field name="res_model">payment.acquirer</field>
<field name='view_type'>form</field>
<field name='view_mode'>tree,form</field>
</record>
<menuitem
action='action_payment_acquirer'
id='payment_acquirer_menu'
parent='root_payment_menu'
sequence='10' />
<record model="ir.ui.view" id="transaction_form">
<field name="model">payment.transaction</field>
<field name="arch" type="xml">
<form string="Payment Transactions" version="7.0">
<group>
<field name="date_create"/>
<field name="date_validate"/>
<field name="acquirer_id"/>
<field name="state"/>
<field name="state_message"/>
<field name="amount"/>
<field name="currency_id"/>
<field name="reference"/>
<field name="name"/>
<field name="partner_id"/>
<field name="partner_name"/>
<field name="partner_email"/>
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="transaction_list">
<field name="model">payment.transaction</field>
<field name="arch" type="xml">
<tree string="Payment Transactions">
<field name="partner_id"/>
<field name="partner_name"/>
<field name="state"/>
<field name="reference"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="transaction">
<field name="model">payment.transaction</field>
<field name="arch" type="xml">
<search>
<field name="partner_id"/>
<field name="partner_name"/>
<field name="reference"/>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_payment_transaction">
<field name="name">Payment Transactions</field>
<field name="res_model">payment.transaction</field>
<field name='view_type'>form</field>
<field name='view_mode'>tree,form</field>
</record>
<menuitem
action='action_payment_transaction'
id='payment_transaction_menu'
parent='root_payment_menu'
sequence='20' />
</data>
</openerp>