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

# -*- 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