ソースを参照

feat: add paytm config, transaction status

pull/2/head
Mangesh-Khairnar 5年前
コミット
3809d5be97
2個のファイルの変更149行の追加99行の削除
  1. +36
    -4
      payments/payment_gateways/doctype/paytm_settings/paytm_settings.json
  2. +113
    -95
      payments/payment_gateways/doctype/paytm_settings/paytm_settings.py

+ 36
- 4
payments/payment_gateways/doctype/paytm_settings/paytm_settings.json ファイルの表示

@@ -6,23 +6,55 @@
"engine": "InnoDB",
"field_order": [
"merchant_id",
"merchant_key"
"merchant_key",
"staging",
"column_break_4",
"industry_type",
"website"
],
"fields": [
{
"fieldname": "merchant_id",
"fieldtype": "Data",
"label": "Merchant ID"
"in_list_view": 1,
"label": "Merchant ID",
"reqd": 1
},
{
"fieldname": "merchant_key",
"fieldtype": "Password",
"in_list_view": 1,
"label": "Merchant Key",
"reqd": 1
},
{
"default": "0",
"fieldname": "staging",
"fieldtype": "Check",
"label": "Staging"
},
{
"depends_on": "eval: !doc.staging",
"fieldname": "industry_type",
"fieldtype": "Data",
"label": "Merchant Key"
"label": "Industry Type",
"mandatory_depends_on": "eval: !doc.staging"
},
{
"depends_on": "eval: !doc.staging",
"fieldname": "website",
"fieldtype": "Data",
"label": "Website",
"mandatory_depends_on": "eval: !doc.staging"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
}
],
"issingle": 1,
"links": [],
"modified": "2020-04-07 19:57:24.126640",
"modified": "2020-04-16 14:16:19.687449",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Paytm Settings",


+ 113
- 95
payments/payment_gateways/doctype/paytm_settings/paytm_settings.py ファイルの表示

@@ -3,16 +3,18 @@
# For license information, please see license.txt

from __future__ import unicode_literals
import json
import requests
from six.moves.urllib.parse import urlencode

import frappe
from frappe.model.document import Document
from frappe import _
from six.moves.urllib.parse import urlencode
from frappe.utils import get_url, call_hook_method, cint, flt
from frappe.utils import get_url, call_hook_method, cint, flt, cstr
from frappe.integrations.utils import make_get_request, make_post_request, create_request_log, create_payment_gateway
from frappe.utils import get_request_site_address

import json
import requests
from frappe.integrations.doctype.paytm_settings.checksum import generate_checksum, verify_checksum
from frappe.utils.password import get_decrypted_password

class PaytmSettings(Document):
supported_currencies = ["INR"]
@@ -44,110 +46,126 @@ class PaytmSettings(Document):

return get_url("./integrations/paytm_checkout?{0}".format(urlencode(kwargs)))

def create_request(self, data):
self.data = frappe._dict(data)

try:
self.integration_request = create_request_log(self.data, "Host", "Paytm")
return self.generate_transaction_token()

except Exception:
frappe.log_error(frappe.get_traceback())
return{
"redirect_to": frappe.redirect_to_message(_('Server Error'), _("It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.")),
"status": 401
}

def generate_transaction_token(self):
import stripe
try:
charge = stripe.Charge.create(amount=cint(flt(self.data.amount)*100), currency=self.data.currency, source=self.data.stripe_token_id, description=self.data.description, receipt_email=self.data.payer_email)

if charge.captured == True:
self.integration_request.db_set('status', 'Completed', update_modified=False)
self.flags.status_changed_to = "Completed"

else:
frappe.log_error(charge.failure_message, 'Stripe Payment not completed')
def get_paytm_config():
''' Returns paytm config '''

except Exception:
frappe.log_error(frappe.get_traceback())
paytm_config = frappe.db.get_singles_dict('Paytm Settings')
paytm_config.update(dict(merchant_key=get_decrypted_password('Paytm Settings', 'Paytm Settings', 'merchant_key')))

return self.finalize_request()
if cint(paytm_config.staging):
paytm_config.update(dict(
website="WEBSTAGING",
url='https://securegw-stage.paytm.in/order/process',
transaction_status_url='https://securegw-stage.paytm.in/order/status',
industry_type_id='RETAIL'
))
else:
paytm_config.update(dict(
url='https://securegw.paytm.in/order/process',
transaction_status_url='https://securegw.paytm.in/order/status',
))
return paytm_config


def finalize_request(self):
redirect_to = self.data.get('redirect_to') or None
redirect_message = self.data.get('redirect_message') or None
status = self.integration_request.status

if self.flags.status_changed_to == "Completed":
if self.data.reference_doctype and self.data.reference_docname:
custom_redirect_to = None
try:
custom_redirect_to = frappe.get_doc(self.data.reference_doctype,
self.data.reference_docname).run_method("on_payment_authorized", self.flags.status_changed_to)
except Exception:
frappe.log_error(frappe.get_traceback())

if custom_redirect_to:
redirect_to = custom_redirect_to

redirect_url = 'payment-success'

if self.redirect_url:
redirect_url = self.redirect_url
redirect_to = None
else:
redirect_url = 'payment-failed'

if redirect_to:
redirect_url += '?' + urlencode({'redirect_to': redirect_to})
if redirect_message:
redirect_url += '&' + urlencode({'redirect_message': redirect_message})

return {
"redirect_to": redirect_url,
"status": status
}

def generate_transaction_token(payment_details, order_id, merchant_id, merchant_key):
def get_paytm_params(payment_details, order_id, paytm_config):

# initialize a dictionary
paytmParams = dict()

redirect_uri = get_request_site_address(True) + "?cmd=frappe.templates.pages.integrations.paytm_checkout.get_transaction_status"
paytm_params = dict()
# redirect_uri = get_request_site_address(True) + "/api/method/frappe.integrations.doctype.paytm_settings.paytm_settings.get_transaction_status"
redirect_uri = "http://cf9b2bb1.ngrok.io/api/method/frappe.integrations.doctype.paytm_settings.paytm_settings.get_transaction_status"

paytm_params.update({
"MID" : paytm_config.merchant_id,
"WEBSITE" : paytm_config.website,
"INDUSTRY_TYPE_ID" : paytm_config.industry_type_id,
"CHANNEL_ID" : "WEB",
"ORDER_ID" : order_id,
"CUST_ID" : payment_details['payer_email'],
"EMAIL" : payment_details['payer_email'],
"TXN_AMOUNT" : cstr(flt(payment_details['amount'], 2)),
"CALLBACK_URL" : redirect_uri,
})

checksum = generate_checksum(paytm_params, paytm_config.merchant_key)

paytm_params.update({
"CHECKSUMHASH" : checksum
})

return paytm_params

@frappe.whitelist(allow_guest=True)
def verify_transaction(**kwargs):
'''Verify checksum for received data in the callback and then verify the transaction'''
paytm_config = get_paytm_config()
received_data = frappe._dict(kwargs)

print(received_data)
paytm_params = {}
for key, value in received_data.items():
if key == 'CHECKSUMHASH':
paytm_checksum = value
else:
paytm_params[key] = value

# body parameters
paytmParams["body"] = get_paytm_params(payment_details, order_id, merchant_id, merchant_key)
# Verify checksum
is_valid_checksum = verify_checksum(paytm_params, paytm_config.merchant_key, paytm_checksum)

checksum = generate_checksum_by_str(json.dumps(paytmParams["body"]), merchant_key)
if is_valid_checksum and received_data['RESPCODE'] == '01':
verify_transaction_status(paytm_config, received_data['ORDERID'])
else:
frappe.respond_as_web_page("Payment Failed",
"Transaction failed to complete. Don't worry, in case of failure amount will get refunded to your account.",
http_status_code=401, indicator_color='red')
frappe.log_error("Order unsuccessful, received data:"+received_data, 'Paytm Payment Failed')

paytmParams["head"] = {
"signature" : checksum
}
def verify_transaction_status(paytm_config, order_id):
'''Verify transaction completion after checksum has been verified'''
paytm_params=dict(
MID=paytm_config.merchant_id,
ORDERID= order_id
)

post_data = json.dumps(paytmParams)
checksum = generate_checksum(paytm_params, paytm_config.merchant_key)
paytm_params["CHECKSUMHASH"] = checksum

url = "https://securegw-stage.paytm.in/theia/api/v1/initiateTransaction?mid={0}&orderId={1}".format(merchant_id, order_id)
post_data = json.dumps(paytm_params)
url = paytm_config.transaction_status_url

response = requests.post(url, data = post_data, headers = {"Content-type": "application/json"}).json()
return response['body'].get('txnToken')
print('transaction status response')
print(response)
finalize_request(order_id, response)

def finalize_request(order_id, response):
request = frappe.db.get_value('Integration Request', order_id)
redirect_to = request.data.get('redirect_to') or None
redirect_message = request.data.get('redirect_message') or None

if request.flags.status_changed_to == "Completed":
if request.data.reference_doctype and request.data.reference_docname:
custom_redirect_to = None
try:
custom_redirect_to = frappe.get_doc(request.data.reference_doctype,
request.data.reference_docname).run_method("on_payment_authorized", request.flags.status_changed_to)
except Exception:
frappe.log_error(frappe.get_traceback())

if custom_redirect_to:
redirect_to = custom_redirect_to

redirect_url = 'payment-success'
else:
redirect_url = 'payment-failed'

if redirect_to:
redirect_url += '?' + urlencode({'redirect_to': redirect_to})
if redirect_message:
redirect_url += '&' + urlencode({'redirect_message': redirect_message})

def get_paytm_params(payment_details, order_id, merchant_id, merchant_key):
return {
"requestType" : "Payment",
"mid" : merchant_id,
"websiteName" : "WEBSTAGING",
"orderId" : order_id,
"callbackUrl" : redirect_uri,
"txnAmount" : {
"value" : flt(payment_details['amount'], 2),
"currency" : "INR",
},
"userInfo" : {
"custId" : payment_details['payer_email'],
},
"redirect_to": redirect_url,
"status": status
}

def get_gateway_controller(doctype, docname):


読み込み中…
キャンセル
保存