-
Notifications
You must be signed in to change notification settings - Fork 1.9k
feat: Adds transaction initiation logic & Payments Manager - PayTM #6342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| # Checksum module from https://github.com/Paytm-Payments/Paytm_Web_Sample_Kit_Python | ||
|
|
||
| import base64 | ||
| import string | ||
| import random | ||
| import hashlib | ||
|
|
||
| from Crypto.Cipher import AES | ||
|
|
||
|
|
||
| IV = "@@@@&&&&####$$$$" | ||
| BLOCK_SIZE = 16 | ||
|
|
||
|
|
||
| def generate_checksum(param_dict, merchant_key, salt=None): | ||
| params_string = __get_param_string__(param_dict) | ||
| salt = salt if salt else __id_generator__(4) | ||
| final_string = '%s|%s' % (params_string, salt) | ||
|
|
||
| hasher = hashlib.sha256(final_string.encode()) | ||
| hash_string = hasher.hexdigest() | ||
|
|
||
| hash_string += salt | ||
|
|
||
| return __encode__(hash_string, IV, merchant_key) | ||
|
|
||
|
|
||
| def generate_refund_checksum(param_dict, merchant_key, salt=None): | ||
| for i in param_dict: | ||
| if("|" in param_dict[i]): | ||
| param_dict = {} | ||
| exit() | ||
| params_string = __get_param_string__(param_dict) | ||
| salt = salt if salt else __id_generator__(4) | ||
| final_string = '%s|%s' % (params_string, salt) | ||
|
|
||
| hasher = hashlib.sha256(final_string.encode()) | ||
| hash_string = hasher.hexdigest() | ||
|
|
||
| hash_string += salt | ||
|
|
||
| return __encode__(hash_string, IV, merchant_key) | ||
|
|
||
|
|
||
| def generate_checksum_by_str(param_str, merchant_key, salt=None): | ||
| params_string = param_str | ||
| salt = salt if salt else __id_generator__(4) | ||
| final_string = '%s|%s' % (params_string, salt) | ||
|
|
||
| hasher = hashlib.sha256(final_string.encode()) | ||
| hash_string = hasher.hexdigest() | ||
|
|
||
| hash_string += salt | ||
|
|
||
| return __encode__(hash_string, IV, merchant_key) | ||
|
|
||
|
|
||
| def verify_checksum(param_dict, merchant_key, checksum): | ||
| # Remove checksum | ||
| if 'CHECKSUMHASH' in param_dict: | ||
| param_dict.pop('CHECKSUMHASH') | ||
|
|
||
| # Get salt | ||
| paytm_hash = __decode__(checksum, IV, merchant_key) | ||
| salt = paytm_hash[-4:] | ||
| calculated_checksum = generate_checksum(param_dict, merchant_key, salt=salt) | ||
| return calculated_checksum == checksum | ||
|
|
||
|
|
||
| def verify_checksum_by_str(param_str, merchant_key, checksum): | ||
| # Get salt | ||
| paytm_hash = __decode__(checksum, IV, merchant_key) | ||
| salt = paytm_hash[-4:] | ||
| calculated_checksum = generate_checksum_by_str(param_str, merchant_key, salt=salt) | ||
| return calculated_checksum == checksum | ||
|
|
||
|
|
||
| def __id_generator__(size=6, chars=string.ascii_uppercase + string.digits + string.ascii_lowercase): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too many blank lines (3) |
||
| return ''.join(random.choice(chars) for _ in range(size)) | ||
|
|
||
|
|
||
| def __get_param_string__(params): | ||
| params_string = [] | ||
| for key in sorted(params.keys()): | ||
| if("REFUND" in params[key] or "|" in params[key]): | ||
| exit() | ||
| value = params[key] | ||
| params_string.append('' if value == 'null' else str(value)) | ||
| return '|'.join(params_string) | ||
|
|
||
|
|
||
| def __pad__(string_literal): | ||
| return (string_literal + (BLOCK_SIZE - len(string_literal) % BLOCK_SIZE) * | ||
| chr(BLOCK_SIZE - len(string_literal) % BLOCK_SIZE)) | ||
|
|
||
|
|
||
| def __unpad__(string_literal): | ||
| return string_literal[0:-ord(string_literal[-1])] | ||
|
|
||
|
|
||
| def __encode__(to_encode, iv, key): | ||
mrsaicharan1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # 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__(to_decode, iv, key): | ||
mrsaicharan1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # 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 __unpad__(to_decode) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| params = { | ||
| "MID": "mid", | ||
| "ORDER_ID": "order_id", | ||
| "CUST_ID": "cust_id", | ||
| "TXN_AMOUNT": "1", | ||
| "CHANNEL_ID": "WEB", | ||
| "INDUSTRY_TYPE_ID": "Retail", | ||
| "WEBSITE": "xxxxxxxxxxx" | ||
| } | ||
|
|
||
| print(verify_checksum( | ||
| params, 'xxxxxxxxxxxxxxxx', | ||
| "CD5ndX8VVjlzjWbbYoAtKQIlvtXPypQYOg0Fi2AUYKXZA5XSHiRF0FDj7vQu6\ | ||
| 6S8MHx9NaDZ/uYm3WBOWHf+sDQAmTyxqUipA7i1nILlxrk=")) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,9 @@ | ||
| import logging | ||
| import json | ||
| import pytz | ||
| from datetime import datetime | ||
| import requests | ||
|
|
||
|
|
||
| import omise | ||
| from flask import request, jsonify, Blueprint, url_for, redirect | ||
|
|
@@ -10,6 +13,7 @@ | |
| from marshmallow_jsonapi.flask import Schema | ||
| from sqlalchemy.orm.exc import NoResultFound | ||
|
|
||
| from app.settings import get_settings | ||
| from app.api.bootstrap import api | ||
| from app.api.data_layers.ChargesLayer import ChargesLayer | ||
| from app.api.helpers.db import save_to_db, safe_query, safe_query_without_soft_deleted_entries | ||
|
|
@@ -22,7 +26,7 @@ | |
| send_notif_ticket_cancel | ||
| from app.api.helpers.order import delete_related_attendees_for_order, set_expiry_for_order, \ | ||
| create_pdf_tickets_for_holder, create_onsite_attendees_for_order | ||
| from app.api.helpers.payment import AliPayPaymentsManager, OmisePaymentsManager | ||
| from app.api.helpers.payment import AliPayPaymentsManager, OmisePaymentsManager, PaytmPaymentsManager | ||
mrsaicharan1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| from app.api.helpers.payment import PayPalPaymentsManager | ||
| from app.api.helpers.permission_manager import has_access | ||
| from app.api.helpers.permissions import jwt_required | ||
|
|
@@ -622,3 +626,45 @@ def omise_checkout(order_identifier): | |
| logging.info(f"Successful charge: {charge.id}. Order ID: {order_identifier}") | ||
|
|
||
| return redirect(make_frontend_url('orders/{}/view'.format(order_identifier))) | ||
|
|
||
|
|
||
| @order_misc_routes.route('/orders/<string:order_identifier>/paytm/initiate-transaction', methods=['POST', 'GET']) | ||
| def initiate_transaction(order_identifier): | ||
| """ | ||
| Initiating a PayTM transaction to obtain the txn token | ||
| :param order_identifier: | ||
| :return: JSON response containing the signature & txn token | ||
| """ | ||
| order = safe_query(db, Order, 'identifier', order_identifier, 'identifier') | ||
| paytm_mode = get_settings()['paytm_mode'] | ||
| paytm_params = {} | ||
| # body parameters | ||
| paytm_params["body"] = { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'paytm_params' |
||
| "requestType": "Payment", | ||
| "mid": (get_settings()['paytm_sandbox_merchant'] if paytm_mode == 'sandbox' | ||
| else get_settings()['paytm_live_merchant']), | ||
| "websiteName": "eventyay", | ||
| "orderId": order.id, | ||
| "callbackUrl": "", | ||
| "txnAmount": { | ||
| "value": order.amount, | ||
| "currency": order.event.payment_currency, | ||
| }, | ||
| "userInfo": { | ||
| "custId": order.user.id, | ||
| }, | ||
| } | ||
| checksum = PaytmPaymentsManager.generate_checksum(paytm_params) | ||
| # head parameters | ||
| paytm_params["head"] = { | ||
| "signature" : checksum | ||
| } | ||
| post_data = json.dumps(paytm_params) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'json' |
||
| if paytm_mode == 'sandbox': | ||
| url = "https://securegw-stage.paytm.in/theia/api/v1/initiateTransaction?mid={}&orderId={}".\ | ||
| format(get_settings()['paytm_sandbox_merchant'], order.id) | ||
| else: | ||
| url = "https://securegw.paytm.in/theia/api/v1/initiateTransaction?mid={}&orderId={}".\ | ||
| format(get_settings()['paytm_sandbox_merchant'], order.id) | ||
| response = requests.post(url, data=post_data, headers={"Content-type": "application/json"}) | ||
| return response.json() | ||
Uh oh!
There was an error while loading. Please reload this page.