You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							217 lines
						
					
					
						
							7.6 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							217 lines
						
					
					
						
							7.6 KiB
						
					
					
				
								# -*- coding: utf-8 -*-
							 | 
						|
								###################################################################################
							 | 
						|
								#
							 | 
						|
								#    Cybrosys Technologies Pvt. Ltd.
							 | 
						|
								#
							 | 
						|
								#    Copyright (C) 2019-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
							 | 
						|
								#    This program is free software: you can modify
							 | 
						|
								#    it under the terms of the GNU Affero General Public License (AGPL) as
							 | 
						|
								#    published by the Free Software Foundation, either version 3 of the
							 | 
						|
								#    License, or (at your option) any later version.
							 | 
						|
								#
							 | 
						|
								#    This program is distributed in the hope that it will be useful,
							 | 
						|
								#    but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						|
								#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						|
								#    GNU Affero General Public License for more details.
							 | 
						|
								#
							 | 
						|
								#    You should have received a copy of the GNU Affero General Public License
							 | 
						|
								#    along with this program.  If not, see <https://www.gnu.org/licenses/>.
							 | 
						|
								#
							 | 
						|
								###################################################################################
							 | 
						|
								
							 | 
						|
								import base64
							 | 
						|
								import string
							 | 
						|
								import random
							 | 
						|
								import hashlib
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								from Crypto.Cipher import AES
							 | 
						|
								from odoo.exceptions import ValidationError
							 | 
						|
								from odoo import api, fields, models
							 | 
						|
								from datetime import datetime
							 | 
						|
								from werkzeug import urls
							 | 
						|
								import hashlib
							 | 
						|
								import json
							 | 
						|
								
							 | 
						|
								import hmac
							 | 
						|
								import base64
							 | 
						|
								
							 | 
						|
								import logging
							 | 
						|
								
							 | 
						|
								_logger = logging.getLogger(__name__)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class PaymentAcquirerAtom(models.Model):
							 | 
						|
								    _inherit = 'payment.acquirer'
							 | 
						|
								
							 | 
						|
								    provider = fields.Selection(selection_add=[('paytm', 'Paytm')])
							 | 
						|
								    paytm_merchant_id = fields.Char('Merchant ID', required_if_provider='Paytm',
							 | 
						|
								                                        groups='base.group_user')
							 | 
						|
								    paytm_merchant_key = fields.Char('Merchent Key', required_if_provider='Paytm',
							 | 
						|
								                                        groups='base.group_user')
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    @api.model
							 | 
						|
								    def _get_paytm_urls(self):
							 | 
						|
								        """ Atom URLS """
							 | 
						|
								        return {
							 | 
						|
								            'paytm_form_url':'https://securegw-stage.paytm.in/order/process'
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def paytm_get_form_action_url(self):
							 | 
						|
								        return self._get_paytm_urls () ['paytm_form_url']
							 | 
						|
								
							 | 
						|
								    def paytm_form_generate_values(self ,values):
							 | 
						|
								        self.ensure_one ()
							 | 
						|
								        base_url=self.env ['ir.config_parameter'].sudo ().get_param ('web.base.url')
							 | 
						|
								        now=datetime.now ()
							 | 
						|
								
							 | 
						|
								        paytm_values=dict (
							 | 
						|
								                          MID=self.paytm_merchant_id ,
							 | 
						|
								                          ORDER_ID=str(values ['reference']) ,
							 | 
						|
								                          CUST_ID = str(values.get('partner_id')),
							 | 
						|
								                          INDUSTRY_TYPE_ID='Retail' ,
							 | 
						|
								                          CHANNEL_ID = 'WEB',
							 | 
						|
								                          TXN_AMOUNT=str(values ['amount']) ,
							 | 
						|
								                          WEBSITE='WEBSTAGING',
							 | 
						|
								                          EMAIL=str(values.get ('partner_email')) ,
							 | 
						|
								                          MOBILE_NO = str(values.get('partner_phone')),
							 | 
						|
								                          CALL_BACK_URL=urls.url_join (base_url ,'/payment/paytm/return/') ,
							 | 
						|
								                          )
							 | 
						|
								
							 | 
						|
								        paytm_values ['reqHashKey']=self.generate_checksum(paytm_values, self.paytm_merchant_key)
							 | 
						|
								        return paytm_values
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def __encode__(self,to_encode ,iv ,key):
							 | 
						|
								        __pad__=lambda s:s + (16 - len (s) % 16) * chr (16 - len (s) % 16)
							 | 
						|
								        # Pad
							 | 
						|
								        to_encode=__pad__ (to_encode)
							 | 
						|
								        # Encrypt
							 | 
						|
								        c=AES.new (key ,AES.MODE_CBC ,iv)
							 | 
						|
								        to_encode=c.encrypt (to_encode)
							 | 
						|
								        # Encode
							 | 
						|
								        to_encode=base64.b64encode (to_encode)
							 | 
						|
								        return to_encode.decode ("UTF-8")
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def __decode__(self,to_decode ,iv ,key):
							 | 
						|
								        # Decode
							 | 
						|
								        to_decode=base64.b64decode (to_decode)
							 | 
						|
								        # Decrypt
							 | 
						|
								        c=AES.new (key ,AES.MODE_CBC ,iv)
							 | 
						|
								        to_decode=c.decrypt (to_decode)
							 | 
						|
								        if type (to_decode) == bytes:
							 | 
						|
								            # convert bytes array to str.
							 | 
						|
								            to_decode=to_decode.decode ()
							 | 
						|
								        # remove pad
							 | 
						|
								        return self.__unpad__ (to_decode)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def __id_generator__(self,size=6 ,chars=string.ascii_uppercase + string.digits + string.ascii_lowercase):
							 | 
						|
								        return ''.join (random.choice (chars) for _ in range (size))
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def __get_param_string__(self,params ,escape_refund=True):
							 | 
						|
								        params_string=[]
							 | 
						|
								        for key in sorted (params.keys ()):
							 | 
						|
								            if ("|" in params [key] or (escape_refund == True and "REFUND" in params [key])):
							 | 
						|
								                respons_dict={}
							 | 
						|
								                exit ()
							 | 
						|
								            value=params [key]
							 | 
						|
								            params_string.append ('' if value == 'null' else str (value))
							 | 
						|
								        return '|'.join (params_string)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def generate_checksum(self,param_dict ,merchant_key ,salt=None):
							 | 
						|
								        params_string=self.__get_param_string__ (param_dict)
							 | 
						|
								        return self.generate_checksum_by_str (params_string ,merchant_key ,salt)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def generate_refund_checksum(self,param_dict ,merchant_key ,salt=None):
							 | 
						|
								        for i in param_dict:
							 | 
						|
								            if ("|" in param_dict [i]):
							 | 
						|
								                param_dict={}
							 | 
						|
								                exit ()
							 | 
						|
								        params_string=self.__get_param_string__ (param_dict ,False)
							 | 
						|
								        return self.generate_checksum_by_str (params_string ,merchant_key ,salt)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def generate_checksum_by_str(self,param_str ,merchant_key ,salt=None):
							 | 
						|
								        IV="@@@@&&&&####$$$$"
							 | 
						|
								        params_string=param_str
							 | 
						|
								        salt=salt if salt else self.__id_generator__ (4)
							 | 
						|
								        final_string='%s|%s' % (params_string ,salt)
							 | 
						|
								
							 | 
						|
								        hasher=hashlib.sha256 (final_string.encode ())
							 | 
						|
								        hash_string=hasher.hexdigest ()
							 | 
						|
								
							 | 
						|
								        hash_string+=salt
							 | 
						|
								
							 | 
						|
								        return self.__encode__ (hash_string ,IV ,merchant_key)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def verify_checksum(self,param_dict ,merchant_key ,checksum):
							 | 
						|
								        # Remove checksum
							 | 
						|
								        if 'CHECKSUMHASH' in param_dict:
							 | 
						|
								            param_dict.pop ('CHECKSUMHASH')
							 | 
						|
								
							 | 
						|
								        params_string=self.__get_param_string__ (param_dict ,False)
							 | 
						|
								        return self.verify_checksum_by_str (params_string ,merchant_key ,checksum)
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def verify_checksum_by_str(self,param_str ,merchant_key ,checksum):
							 | 
						|
								        IV="@@@@&&&&####$$$$"
							 | 
						|
								        paytm_hash=self.__decode__ (checksum ,IV ,merchant_key)
							 | 
						|
								        salt=paytm_hash [-4:]
							 | 
						|
								        calculated_checksum=self.generate_checksum_by_str (param_str ,merchant_key ,salt=salt)
							 | 
						|
								        return calculated_checksum == checksum
							 | 
						|
								
							 | 
						|
								class PaymentTransactionAtom(models.Model):
							 | 
						|
								    _inherit = 'payment.transaction'
							 | 
						|
								
							 | 
						|
								    paytm_txn_type = fields.Char('Transaction type')
							 | 
						|
								
							 | 
						|
								    @api.model
							 | 
						|
								    def _paytm_form_get_tx_from_data(self ,data):
							 | 
						|
								        reference =data.get ('ORDERID')
							 | 
						|
								        if not reference:
							 | 
						|
								            error_msg=_ ('Paytm: received data with missing reference (%s)') % (reference)
							 | 
						|
								            _logger.info (error_msg)
							 | 
						|
								            raise ValidationError (error_msg)
							 | 
						|
								
							 | 
						|
								        txs=self.env ['payment.transaction'].search ([('reference' ,'=' ,reference)])
							 | 
						|
								        if not txs or len (txs) > 1:
							 | 
						|
								            error_msg='Paytm: received data for reference %s' % (reference)
							 | 
						|
								            if not txs:
							 | 
						|
								                error_msg+='; no order found'
							 | 
						|
								            else:
							 | 
						|
								                error_msg+='; multiple order found'
							 | 
						|
								            _logger.info (error_msg)
							 | 
						|
								            raise ValidationError (error_msg)
							 | 
						|
								        return txs [0]
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def _paytm_form_get_invalid_parameters(self ,data):
							 | 
						|
								        invalid_parameters=[]
							 | 
						|
								        if self.acquirer_reference and data.get ('mmp_txn') != self.acquirer_reference:
							 | 
						|
								            invalid_parameters.append (('ORDERID' ,data.get ('ORDERID') ,self.acquirer_reference))
							 | 
						|
								
							 | 
						|
								        return invalid_parameters
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    def _paytm_form_validate(self ,data):
							 | 
						|
								        status=data.get ('STATUS')
							 | 
						|
								        result=self.write ({
							 | 
						|
								            'acquirer_reference':self.env ['payment.acquirer'].search ([]) ,
							 | 
						|
								            'date':fields.Datetime.now () ,
							 | 
						|
								
							 | 
						|
								        })
							 | 
						|
								        if status == 'TXN_SUCCESS':
							 | 
						|
								            self._set_transaction_done ()
							 | 
						|
								        elif status != 'TXN_FAILED':
							 | 
						|
								            self._set_transaction_cancel ()
							 | 
						|
								        else:
							 | 
						|
								            self._set_transaction_pending ()
							 | 
						|
								        return result
							 |