[FIX] [IMP] paypal
authorThibault Delavallée <tde@openerp.com>
Wed, 4 Dec 2013 16:07:38 +0000 (17:07 +0100)
committerThibault Delavallée <tde@openerp.com>
Wed, 4 Dec 2013 16:07:38 +0000 (17:07 +0100)
- 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

addons/payment_acquirer_paypal/controllers/main.py
addons/payment_acquirer_paypal/data/paypal.xml
addons/payment_acquirer_paypal/models/paypal.py
addons/payment_acquirer_paypal/views/payment_acquirer.xml

index 2fdb193..d5ec939 100644 (file)
@@ -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)
index 15a5c4d..5524580 100644 (file)
@@ -10,7 +10,7 @@
 <p>You will be redirected to the Paypal website after cliking on the payment button.</p>]]></field>
             <field name="paypal_tx_url">https://www.sandbox.paypal.com/cgi-bin/webscr</field>
             <field name="paypal_email_id">dummy</field>
-            <field name="paypal_username">dummy</field>
+            <field name="paypal_seller_id">dummy</field>
             <field name="paypal_api_username">dummy</field>
             <field name="paypal_api_password">dummy</field>
         </record>
index 371b442..8a9fac7 100644 (file)
@@ -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
index 1ccd18e..0c00ee3 100644 (file)
@@ -12,7 +12,7 @@
                         <group>
                             <group>
                                 <field name="paypal_email_id"/>
-                                <field name="paypal_username"/>
+                                <field name="paypal_seller_id"/>
                                 <field name="paypal_use_ipn"/>
                                 <field name="paypal_api_enabled"/>
                                 <field name="paypal_api_username"