# -*- coding: utf-8 -*- ################################################################################### # # Cybrosys Technologies Pvt. Ltd. # # Copyright (C) 2019-TODAY Cybrosys Technologies(). # 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 . # ################################################################################### 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' } @api.multi def paytm_get_form_action_url(self): return self._get_paytm_urls () ['paytm_form_url'] # def _paytm_generate_sign(self ,inout ,values): # if inout not in ('in' ,'out'): # raise Exception ("Type must be 'in' or 'out'") # # if inout == 'in': # keys="merchant_id|merchant_key|txnid|ttype|prodid|amt||||||||||".split ('|') # sign=''.join ('%s|' % (values.get (k) or '') for k in keys) # sign+=self.paytm_merchant_key or '' # else: # keys="|status|||||||||||amt|prodid|ttype|txnid".split ('|') # sign=''.join ('%s|' % (values.get (k) or '') for k in keys) # sign=self.paytm_merchant_key + sign + self.paytm_merchant_id # # shasign=hashlib.sha512 (sign.encode ('utf-8')).hexdigest () # return shasign @api.multi def paytm_form_generate_values(self ,values): self.ensure_one () print("values", values) 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) print(paytm_values ['reqHashKey']) return paytm_values @api.multi 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") @api.multi 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) @api.multi def __id_generator__(self,size=6 ,chars=string.ascii_uppercase + string.digits + string.ascii_lowercase): return ''.join (random.choice (chars) for _ in range (size)) @api.multi def __get_param_string__(self,params ,escape_refund=True): params_string=[] print(params) for key in sorted (params.keys ()): print(key) 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) @api.multi 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) @api.multi 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) @api.multi 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) @api.multi 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) @api.multi 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): print ("dataa" ,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] @api.multi 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 @api.multi def _paytm_form_validate(self ,data): print (data) status=data.get ('STATUS') result=self.write ({ 'acquirer_reference':self.env ['payment.acquirer'].search ([]) , 'date':fields.Datetime.now () , }) print (status) if status == 'TXN_SUCCESS': self._set_transaction_done () elif status != 'TXN_FAILED': self._set_transaction_cancel () else: self._set_transaction_pending () return result