seitime-frappe/frappe/integrations/razorpay.py
2016-09-19 18:11:27 +05:30

200 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
"""
# Integrating RazorPay
### Validate Currency
Example:
from frappe.integration_broker.doctype.integration_service.integration_service import get_integration_controller
controller = get_integration_controller("Razorpay", setup=False)
controller().validate_transaction_currency(currency)
### 2. Redirect for payment
Example:
payment_details = {
"amount": 600,
"title": "Payment for bill : 111",
"description": "payment via cart",
"reference_doctype": "Payment Request",
"reference_docname": "PR0001",
"payer_email": "NuranVerkleij@example.com",
"payer_name": "Nuran Verkleij",
"order_id": "111",
"currency": "INR"
}
from frappe.integration.razorpay import get_checkout_url
# Redirect the user to this url
url = controller().get_payment_url(**payment_details)
### 3. On Completion of Payment
Write a method for `on_payment_authorized` in the reference doctype
Example:
def on_payment_authorized(payment_status):
# this method will be called when payment is complete
##### Notes:
payment_status - payment gateway will put payment status on callback.
For razorpay payment status is Authorized
"""
from __future__ import unicode_literals
import frappe
from frappe import _
import urllib, json
from frappe.utils import get_url, call_hook_method
from frappe.integration_broker.integration_controller import IntegrationController
class Controller(IntegrationController):
service_name = 'Razorpay'
parameters_template = [
{
"label": "API Key",
'fieldname': 'api_key',
'fieldtype': "Data",
'reqd': 1
},
{
"label": "API Secret",
'fieldname': 'api_secret',
'fieldtype': "Password",
'reqd': 1
}
]
# do also changes in razorpay.js scheduler job helper
scheduled_jobs = [
{
"all": [
"frappe.integrations.razorpay.capture_payment"
]
}
]
js = "assets/frappe/js/integrations/razorpay.js"
supported_currencies = ["INR"]
def enable(self, parameters, use_test_account=0):
call_hook_method('payment_gateway_enabled', gateway='Razorpay')
self.parameters = parameters
self.validate_razorpay_credentails()
def validate_razorpay_credentails(self):
razorpay_settings = self.get_settings()
if razorpay_settings.get("api_key"):
try:
self.get_request(url="https://api.razorpay.com/v1/payments",
auth=(razorpay_settings.api_key, razorpay_settings.api_secret))
except Exception:
frappe.throw(_("Seems API Key or API Secret is wrong !!!"))
def validate_transaction_currency(self, currency):
if currency not in self.supported_currencies:
frappe.throw(_("Please select another payment method. {0} does not support transactions in currency '{1}'").format(self.service_name, currency))
def get_payment_url(self, **kwargs):
return get_url("./integrations/razorpay_checkout?{0}".format(urllib.urlencode(kwargs)))
def get_settings(self):
if hasattr(self, "parameters"):
return frappe._dict(self.parameters)
custom_settings_json = frappe.db.get_value("Integration Service", "Razorpay", "custom_settings_json")
if custom_settings_json:
return frappe._dict(json.loads(custom_settings_json))
def create_request(self, data):
self.data = frappe._dict(data)
try:
self.integration_request = super(Controller, self).create_request(self.data, "Host", \
self.service_name)
return self.authorize_payment()
except Exception:
return{
"redirect_to": frappe.redirect_to_message(_('Server Error'), _("Seems issue with server's razorpay config. Don't worry, in case of failure amount will get refunded to your account.")),
"status": 401
}
def authorize_payment(self):
"""
An authorization is performed when users payment details are successfully authenticated by the bank.
The money is deducted from the customers account, but will not be transferred to the merchants account
until it is explicitly captured by merchant.
"""
settings = self.get_settings()
if self.integration_request.status != "Authorized":
resp = self.get_request("https://api.razorpay.com/v1/payments/{0}"
.format(self.data.razorpay_payment_id), auth=(settings.api_key,
settings.api_secret))
if resp.get("status") == "authorized":
self.integration_request.db_set('status', 'Authorized', update_modified=False)
self.flags.status_changed_to = "Authorized"
if self.flags.status_changed_to == "Authorized":
if self.data.reference_doctype and self.data.reference_docname:
redirect_to = frappe.get_doc(self.data.reference_doctype, self.data.reference_docname).run_method("on_payment_authorized", self.flags.status_changed_to)
return {
"redirect_to": redirect_to or "payment-success",
"status": 200
}
def capture_payment(is_sandbox=False, sanbox_response=None):
"""
Verifies the purchase as complete by the merchant.
After capture, the amount is transferred to the merchant within T+3 days
where T is the day on which payment is captured.
Note: Attempting to capture a payment whose status is not authorized will produce an error.
"""
controller = frappe.get_doc("Integration Service", "Razorpay")
settings = controller.get_parameters()
for doc in frappe.get_all("Integration Request", filters={"status": "Authorized",
"integration_request_service": "Razorpay"}, fields=["name", "data"]):
try:
if is_sandbox:
resp = sanbox_response
else:
data = json.loads(doc.data)
resp = controller.post_request("https://api.razorpay.com/v1/payments/{0}/capture".format(data.get("razorpay_payment_id")),
auth=(settings["api_key"], settings["api_secret"]), data={"amount": data.get("amount")})
if resp.get("status") == "captured":
frappe.db.set_value("Integration Request", doc.name, "status", "Completed")
except Exception:
doc = frappe.get_doc("Integration Request", doc.name)
doc.status = "Failed"
doc.error = frappe.get_traceback()
@frappe.whitelist(allow_guest=True, xss_safe=True)
def get_checkout_url(**kwargs):
try:
return Controller().get_payment_url(**kwargs)
except Exception:
frappe.respond_as_web_page(_("Something went wrong"),
_("Looks like something is wrong with this site's Razorpay configuration. Don't worry! No payment has been made."),
success=False,
http_status_code=frappe.ValidationError.http_status_code)