[IMP] [WIP] payment_acquirer_paypal: improved server2server communication + tests. Commit WIP for backup.

bzr revid: tde@openerp.com-20131122163256-f4l8b2kcrtzus56s
This commit is contained in:
Thibault Delavallée
2013-11-22 17:32:56 +01:00
parent b6836ceb5b
commit e530dc0ab3
3 changed files with 242 additions and 26 deletions
@@ -295,6 +295,67 @@ class PaymentTransaction(osv.Model):
# SERVER2SERVER RELATED METHODS
# --------------------------------------------------
def create_s2s(self, cr, uid, tx_values, cc_values, context=None):
tx_id = self.create(cr, uid, tx_values, context=context)
def s2s_create(self, cr, uid, values, cc_values, context=None):
tx_id, tx_result = self.s2s_send(cr, uid, values, cc_values, context=context)
self.s2s_feedback(cr, uid, tx_id, tx_result, context=context)
return tx_id
def s2s_send(self, cr, uid, values, cc_values, context=None):
""" Create and send server-to-server transaction.
:param dict values: transaction values
:param dict cc_values: credit card values that are not stored into the
payment.transaction object. Acquirers should
handle receiving void or incorrect cc values.
Should contain :
- holder_name
- number
- cvc
- expiry_date
- brand
- expiry_date_yy
- expiry_date_mm
"""
tx_id, result = None, None
if values.get('acquirer_id'):
acquirer = self.pool['payment.acquirer'].browse(cr, uid, values.get('acquirer_id'), context=context)
custom_method_name = '_%s_s2s_send' % acquirer.name
if hasattr(self, custom_method_name):
tx_id, result = getattr(self, custom_method_name)(cr, uid, values, cc_values, context=context)
if tx_id is None and result is None:
tx_id = super(PaymentTransaction, self).create(cr, uid, values, context=context)
return (tx_id, result)
def s2s_feedback(self, cr, uid, tx_id, data, context=None):
""" Handle the feedback of a server-to-server transaction. """
tx = self.browse(cr, uid, tx_id, context=context)
invalid_parameters = None
invalid_param_method_name = '_%s_s2s_get_invalid_parameters' % tx.acquirer_id.name
if hasattr(self, invalid_param_method_name):
invalid_parameters = getattr(self, invalid_param_method_name)(cr, uid, tx, data, context=context)
if invalid_parameters:
_error_message = '%s: incorrect tx data:\n' % (tx.acquirer_id.name)
for item in invalid_parameters:
_error_message += '\t%s: received %s instead of %s\n' % (item[0], item[1], item[2])
_logger.error(_error_message)
return False
feedback_method_name = '_%s_s2s_validate' % tx.acquirer_id.name
if hasattr(self, feedback_method_name):
return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context)
return True
def s2s_get_tx_status(self, cr, uid, tx_id, context=None):
tx = self.browse(cr, uid, tx_id, context=context)
invalid_param_method_name = '_%s_s2s_get_tx_status' % tx.acquirer_id.name
if hasattr(self, invalid_param_method_name):
return getattr(self, invalid_param_method_name)(cr, uid, tx, context=context)
return True
+87 -16
View File
@@ -82,7 +82,7 @@ class AcquirerPaypal(osv.Model):
for explanation why we use Authorization header instead of urllib2
password manager
"""
res = dict()
res = dict.fromkeys(ids, False)
parameters = urllib.urlencode({'grant_type': 'client_credentials'})
request = urllib2.Request('https://api.sandbox.paypal.com/v1/oauth2/token', parameters)
# add other headers (https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/)
@@ -226,7 +226,7 @@ class TxPaypal(osv.Model):
# SERVER2SERVER RELATED METHODS
# --------------------------------------------------
def paypal_s2s_create(self, cr, uid, values, context=None):
def _paypal_s2s_send(self, cr, uid, values, cc_values, context=None):
tx_id = self.create(cr, uid, values, context=context)
tx = self.browse(cr, uid, tx_id, context=context)
@@ -236,25 +236,96 @@ class TxPaypal(osv.Model):
}
data = {
'intent': 'sale',
'redirect_urls': {
'transactions': [{
'amount': {
'total': '%.2f' % tx.amount,
'currency': tx.currency_id.name,
},
'description': tx.reference,
}]
}
if cc_values:
data['payer'] = {
'payment_method': 'credit_card',
'funding_instruments': [{
'credit_card': {
'number': cc_values['number'],
'type': cc_values['brand'],
'expire_month': cc_values['expiry_mm'],
'expire_year': cc_values['expiry_yy'],
'cvv2': cc_values['cvc'],
'first_name': tx.partner_name,
'last_name': tx.partner_name,
'billing_address': {
'line1': tx.partner_address,
'city': tx.partner_city,
'country_code': tx.partner_country_id.code,
'postal_code': tx.partner_zip,
}
}
}]
}
else:
data['redirect_urls'] = {
'return_url': 'http://example.com/your_redirect_url/',
'cancel_url': 'http://example.com/your_cancel_url/',
},
'payer': {
data['payer'] = {
'payment_method': 'paypal',
},
'transactions': [
{
'amount': {
'total': '7.47',
'currency': 'USD',
}
}
]
}
}
data = json.dumps(data)
request = urllib2.Request('https://api.sandbox.paypal.com/v1/payments/payment', data, headers)
result = urllib2.urlopen(request).read()
return result
result = urllib2.urlopen(request)
print 'result', result
res2 = result.read()
print res2
return (tx_id, res2)
def _paypal_s2s_get_invalid_parameters(self, cr, uid, tx, data, context=None):
invalid_parameters = []
return invalid_parameters
def _paypal_s2s_validate(self, cr, uid, tx, data, context=None):
values = json.loads(data)
status = values.get('state')
if status in ['approved']:
_logger.info('Validated Paypal s2s payment for tx %s: set as done' % (tx.reference))
tx.write({
'state': 'done',
'date_validate': values.get('udpate_time', fields.datetime.now()),
'paypal_txn_id': values['id'],
})
return True
elif status in ['pending', 'expired']:
_logger.info('Received notification for Paypal s2s payment %s: set as pending' % (tx.reference))
tx.write({
'state': 'pending',
# 'state_message': data.get('pending_reason', ''),
'paypal_txn_id': values['id'],
})
return True
else:
error = 'Received unrecognized status for Paypal s2s payment %s: %s, set as error' % (tx.reference, status)
_logger.info(error)
tx.write({
'state': 'error',
# 'state_message': error,
'paypal_txn_id': values['id'],
})
return False
def _paypal_s2s_get_tx_status(self, cr, uid, tx, context=None):
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer %s' % tx.acquirer_id._paypal_s2s_get_access_token()[tx.acquirer_id.id],
}
data = json.dumps({})
url = 'https://api.sandbox.paypal.com/v1/payments/payment/%s' % (tx.paypal_txn_id)
print url
request = urllib2.Request(url, data, headers)
result = urllib2.urlopen(request)
print result
return True
@@ -7,10 +7,6 @@ from openerp.osv.orm import except_orm
from openerp.tools import mute_logger
from lxml import objectify
# import requests
# import urlparse
import urllib
import urllib2
import urlparse
@@ -37,6 +33,18 @@ class PaypalCommon(PaymentAcquirerCommon):
})
# tde+seller@openerp.com - tde+buyer@openerp.com - tde+buyer-it@openerp.com
# some CC
self.amex = (('378282246310005', '123'), ('371449635398431', '123'))
self.amex_corporate = (('378734493671000', '123'))
self.autralian_bankcard = (('5610591081018250', '123'))
self.dinersclub = (('30569309025904', '123'), ('38520000023237', '123'))
self.discover = (('6011111111111117', '123'), ('6011000990139424', '123'))
self.jcb = (('3530111333300000', '123'), ('3566002020360505', '123'))
self.mastercard = (('5555555555554444', '123'), ('5105105105105100', '123'))
self.visa = (('4111111111111111', '123'), ('4012888888881881', '123'), ('4222222222222', '123'))
self.dankord_pbs = (('76009244561', '123'), ('5019717010103742', '123'))
self.switch_polo = (('6331101999990016', '123'))
class PaypalServer2Server(PaypalCommon):
@@ -44,18 +52,94 @@ class PaypalServer2Server(PaypalCommon):
cr, uid, context = self.cr, self.uid, {}
res = self.payment_acquirer._paypal_s2s_get_access_token(cr, uid, [self.paypal_id], context=context)
print res, res.get('access_token')
self.assertTrue(res[self.paypal_id] is not False, 'paypal: did not generate access token')
res = self.payment_transaction.paypal_s2s_create(
tx_id = self.payment_transaction.s2s_create(
cr, uid, {
'amount': 0.01,
'acquirer_id': self.paypal_id,
'currency_id': self.currency_euro_id,
'reference': 'test_reference',
'paypal_txn_id': '61E67681CH3238416',
'partner_id': self.buyer_id,
}, {
'number': self.visa[0][0],
'cvc': self.visa[0][1],
'brand': 'visa',
'expiry_mm': 9,
'expiry_yy': 2015,
}, context=context
)
print res
tx = self.payment_transaction.browse(cr, uid, tx_id, context=context)
print tx.paypal_txn_id
self.payment_transaction.s2s_get_tx_status(cr, uid, tx_id, context=context)
# {
# "id":"PAY-2LL14628DB722091TKKHXZHQ",
# "create_time":"2013-11-22T15:47:42Z",
# "update_time":"2013-11-22T15:48:05Z",
# "state":"pending",
# "intent":"sale",
# "payer": {
# "payment_method":"credit_card",
# "funding_instruments": [{
# "credit_card": {
# "type":"visa",
# "number":"xxxxxxxxxxxx1111",
# "expire_month":"9",
# "expire_year":"2015",
# "first_name":"Norbert Buyer",
# "last_name":"Norbert Buyer",
# "billing_address": {
# "line1":"Huge Street 2/543",
# "city":"Sin City",
# "postal_code":"1000",
# "country_code":"BE"
# }
# }
# }]
# },
# "transactions": [{
# "amount": {
# "total":"0.01",
# "currency":"EUR",
# "details": {
# "subtotal":"0.01"
# }
# },
# "related_resources": [{
# "sale": {
# "id":"4KU52719R3958614J",
# "create_time":"2013-11-22T15:47:42Z",
# "update_time":"2013-11-22T15:48:05Z",
# "state":"pending",
# "amount": {
# "total":"0.01",
# "currency":"EUR"
# },
# "pending_reason":"multicurrency",
# "parent_payment":"PAY-2LL14628DB722091TKKHXZHQ",
# "links": [{
# "href":"https://api.sandbox.paypal.com/v1/payments/sale/4KU52719R3958614J",
# "rel":"self",
# "method":"GET"
# },{
# "href":"https://api.sandbox.paypal.com/v1/payments/sale/4KU52719R3958614J/refund",
# "rel":"refund",
# "method":"POST"
# },{
# "href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-2LL14628DB722091TKKHXZHQ",
# "rel":"parent_payment",
# "method":"GET"
# }]
# }
# }]
# }],
# "links": [{
# "href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-2LL14628DB722091TKKHXZHQ",
# "rel":"self",
# "method":"GET"
# }]
# }
class PaypalForm(PaypalCommon):