From e0d1233f485ff30f94a67c90ba681fc929a61a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 4 Dec 2013 17:07:38 +0100 Subject: [PATCH] [FIX] [IMP] paypal - fixed controller: when using urlopen and read, the response is already a text (bug coming from the removal of requests lib) - cleaned and fixed paypal data validation, now working - remove paypal_username field, not used; added paypal_seller_id that is the unique ID of the seller, to check that paypal data is correct - various code cleaning bzr revid: tde@openerp.com-20131204160738-q9paazleyg5v5hjo --- .../controllers/main.py | 30 ++++---- .../payment_acquirer_paypal/data/paypal.xml | 2 +- .../payment_acquirer_paypal/models/paypal.py | 69 ++++++++----------- .../views/payment_acquirer.xml | 2 +- 4 files changed, 46 insertions(+), 57 deletions(-) diff --git a/addons/payment_acquirer_paypal/controllers/main.py b/addons/payment_acquirer_paypal/controllers/main.py index 2fdb193dd1c..d5ec93909af 100644 --- a/addons/payment_acquirer_paypal/controllers/main.py +++ b/addons/payment_acquirer_paypal/controllers/main.py @@ -21,6 +21,14 @@ class PaypalController(http.Controller): _return_url = '/payment/paypal/dpn/' _cancel_url = '/payment/paypal/cancel/' + def _get_return_url(self, **post): + """ Extract the return URL from the data coming from paypal. """ + return_url = post.pop('return_url', '') + if not return_url: + custom = json.loads(post.pop('custom', '{}')) + return_url = custom.get('return_url', '/') + return return_url + def paypal_validate_data(self, **post): """ Paypal IPN: three steps validation to ensure data correctness @@ -36,11 +44,11 @@ class PaypalController(http.Controller): urequest = urllib2.Request("https://www.sandbox.paypal.com/cgi-bin/webscr", urllib.urlencode(new_post)) uopen = urllib2.urlopen(urequest) resp = uopen.read() - if resp.text == 'VERIFIED': + if resp == 'VERIFIED': _logger.info('Paypal: validated data') cr, uid, context = request.cr, request.uid, request.context res = request.registry['payment.transaction'].form_feedback(cr, uid, post, 'paypal', context=context) - elif resp.text == 'INVALID': + elif resp == 'INVALID': _logger.warning('Paypal: answered INVALID on data verification') else: _logger.warning('Paypal: unrecognized paypal answer, received %s instead of VERIFIED or INVALID' % resp.text) @@ -48,7 +56,7 @@ class PaypalController(http.Controller): @website.route([ '/payment/paypal/ipn/', - ], type='http', auth='public') + ], type='http', auth='public', methods=['POST']) def paypal_ipn(self, **post): """ Paypal IPN. """ _logger.info('Beginning Paypal IPN form_feedback with post data %s', pprint.pformat(post)) # debug @@ -57,14 +65,11 @@ class PaypalController(http.Controller): @website.route([ '/payment/paypal/dpn', - ], type='http', auth="public") + ], type='http', auth="public", methods=['POST']) def paypal_dpn(self, **post): """ Paypal DPN """ _logger.info('Beginning Paypal DPN form_feedback with post data %s', pprint.pformat(post)) # debug - return_url = post.pop('return_url', '') - if not return_url: - custom = json.loads(post.pop('custom', '{}')) - return_url = custom.pop('return_url', '/') + return_url = self._get_return_url(**post) self.paypal_validate_data(**post) return request.redirect(return_url) @@ -72,11 +77,8 @@ class PaypalController(http.Controller): '/payment/paypal/cancel', ], type='http', auth="public") def paypal_cancel(self, **post): - """ TODO - """ + """ When the user cancels its Paypal payment: GET on this route """ cr, uid, context = request.cr, request.uid, request.context - print 'Entering paypal_cancel with post', post - - return_url = post.pop('return_url', '/') - print 'return_url', return_url + _logger.info('Beginning Paypal cancel with post data %s', pprint.pformat(post)) # debug + return_url = self._get_return_url(**post) return request.redirect(return_url) diff --git a/addons/payment_acquirer_paypal/data/paypal.xml b/addons/payment_acquirer_paypal/data/paypal.xml index 15a5c4dfcf7..55245804975 100644 --- a/addons/payment_acquirer_paypal/data/paypal.xml +++ b/addons/payment_acquirer_paypal/data/paypal.xml @@ -10,7 +10,7 @@

You will be redirected to the Paypal website after cliking on the payment button.

]]> https://www.sandbox.paypal.com/cgi-bin/webscr dummy - dummy + dummy dummy dummy diff --git a/addons/payment_acquirer_paypal/models/paypal.py b/addons/payment_acquirer_paypal/models/paypal.py index 371b4423eda..8a9fac7cc46 100644 --- a/addons/payment_acquirer_paypal/models/paypal.py +++ b/addons/payment_acquirer_paypal/models/paypal.py @@ -36,7 +36,7 @@ class AcquirerPaypal(osv.Model): _columns = { 'paypal_email_id': fields.char('Email ID', required_if_provider='paypal'), - 'paypal_username': fields.char('Username', required_if_provider='paypal'), + 'paypal_seller_id': fields.char('Seller ID', required_if_provider='paypal'), 'paypal_use_ipn': fields.boolean('Use IPN'), # Server 2 server 'paypal_api_enabled': fields.boolean('Use Rest API'), @@ -168,9 +168,8 @@ class TxPaypal(osv.Model): return self.browse(cr, uid, tx_ids[0], context=context) def _paypal_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): - # TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details invalid_parameters = [] - if data.get('notify_version')[0] != '2.6': + if data.get('notify_version')[0] != '3.4': _logger.warning( 'Received a notification from Paypal with version %s instead of 2.6. This could lead to issues when managing it.' % data.get('notify_version') @@ -179,60 +178,48 @@ class TxPaypal(osv.Model): _logger.warning( 'Received a notification from Paypal using sandbox' ), + + # TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details + if tx.acquirer_reference and data.get('txn_id') != tx.acquirer_reference: + invalid_parameters.append(('txn_id', data.get('txn_id'), tx.acquirer_reference)) # check what is buyed - if float_compare(float(data.get('mc_gross', '0.0')), tx.amount, 2) != 0: - invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount)) + if float_compare(float(data.get('mc_gross', '0.0')), (tx.amount + tx.fees), 2) != 0: + invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount)) # mc_gross is amount + fees if data.get('mc_currency') != tx.currency_id.name: - invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name)) - # if parameters.get('payment_fee') != tx.payment_fee: - # invalid_parameters.append(('payment_fee', tx.payment_fee)) - # if parameters.get('quantity') != tx.quantity: - # invalid_parameters.append(('mc_currency', tx.quantity)) - # if parameters.get('shipping') != tx.shipping: - # invalid_parameters.append(('shipping', tx.shipping)) + invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name)) + if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), tx.fees, 2) != 0: + invalid_parameters.append(('handling_amount', data.get('handling_amount'), tx.fees)) # check buyer - # if parameters.get('payer_id') != tx.payer_id: - # invalid_parameters.append(('mc_gross', tx.payer_id)) - # if parameters.get('payer_email') != tx.payer_email: - # invalid_parameters.append(('payer_email', tx.payer_email)) + if tx.partner_reference and data.get('payer_id') != tx.partner_reference: + invalid_parameters.append(('payer_id', data.get('payer_id'), tx.partner_reference)) # check seller - # if parameters.get('receiver_email') != tx.receiver_email: - # invalid_parameters.append(('receiver_email', tx.receiver_email)) - # if parameters.get('receiver_id') != tx.receiver_id: - # invalid_parameters.append(('receiver_id', tx.receiver_id)) + if data.get('receiver_email') != tx.acquirer_id.paypal_email_id: + invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_id)) + if data.get('receiver_id') != tx.acquirer_id.paypal_seller_id: + invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_id)) return invalid_parameters def _paypal_form_validate(self, cr, uid, tx, data, context=None): status = data.get('payment_status') + data = { + 'acquirer_reference': data.get('txn_id'), + 'paypal_txn_type': data.get('payment_type'), + 'partner_reference': data.get('payer_id') + } if status in ['Completed', 'Processed']: _logger.info('Validated Paypal payment for tx %s: set as done' % (tx.reference)) - tx.write({ - 'state': 'done', - 'date_validate': data.get('payment_date', fields.datetime.now()), - 'paypal_txn_id': data['txn_id'], - 'paypal_txn_type': data.get('express_checkout'), - }) - return True + data.update(state='done', date_validate=data.get('payment_date', fields.datetime.now())) + return tx.write(data) elif status in ['Pending', 'Expired']: _logger.info('Received notification for Paypal payment %s: set as pending' % (tx.reference)) - tx.write({ - 'state': 'pending', - 'state_message': data.get('pending_reason', ''), - 'paypal_txn_id': data['txn_id'], - 'paypal_txn_type': data.get('express_checkout'), - }) - return True + data.udpate(state='pending', state_message=data.get('pending_reason', '')) + return tx.write(data) else: error = 'Received unrecognized status for Paypal payment %s: %s, set as error' % (tx.reference, status) _logger.info(error) - tx.write({ - 'state': 'error', - 'state_message': error, - 'paypal_txn_id': data['txn_id'], - 'paypal_txn_type': data.get('express_checkout'), - }) - return False + data.update(state='error', state_message=error) + return tx.write(data) # -------------------------------------------------- # SERVER2SERVER RELATED METHODS diff --git a/addons/payment_acquirer_paypal/views/payment_acquirer.xml b/addons/payment_acquirer_paypal/views/payment_acquirer.xml index 1ccd18e29b9..0c00ee37261 100644 --- a/addons/payment_acquirer_paypal/views/payment_acquirer.xml +++ b/addons/payment_acquirer_paypal/views/payment_acquirer.xml @@ -12,7 +12,7 @@ - +