* [fix] refactor integration services * [fix] patch fix * [fix] added redirect url. * [fix] custom redirect to and reditect message for paypal and service setup information * [minor][fix] remove ldap dependancy from requirementspull/2/head
@@ -0,0 +1,31 @@ | |||
// Copyright (c) 2016, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.provide("frappe.integration_service") | |||
frappe.ui.form.on('PayPal Settings', { | |||
refresh: function(frm) { | |||
} | |||
}); | |||
frappe.integration_service.paypal_settings = Class.extend({ | |||
init: function(frm) { | |||
}, | |||
get_scheduler_job_info: function() { | |||
return {} | |||
}, | |||
get_service_info: function(frm) { | |||
frappe.call({ | |||
method: "frappe.integrations.doctype.paypal_settings.paypal_settings.get_service_details", | |||
callback: function(r){ | |||
var integration_service_help = frm.fields_dict.integration_service_help.wrapper; | |||
$(integration_service_help).empty(); | |||
$(integration_service_help).append(r.message); | |||
} | |||
}) | |||
} | |||
}) |
@@ -0,0 +1,190 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"beta": 0, | |||
"creation": "2016-09-21 08:03:01.009852", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "System", | |||
"editable_grid": 1, | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "api_username", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "API Username", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "api_password", | |||
"fieldtype": "Password", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "API Password", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "signature", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Signature", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Check this if you are testing your payment using the Sandbox API", | |||
"fieldname": "paypal_sandbox", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Use Sandbox", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Mention transaction completion page URL", | |||
"fieldname": "redirect_to", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Redirect To", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 1, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-09-26 02:00:45.145155", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "PayPal Settings", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 0, | |||
"role": "System Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 1, | |||
"read_only_onload": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,274 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import json | |||
from frappe import _ | |||
from frappe.utils import get_url, call_hook_method | |||
from urllib import urlencode | |||
from frappe.integration_broker.doctype.integration_service.integration_service import IntegrationService | |||
import urllib | |||
""" | |||
# Integrating PayPal | |||
### 1. Validate Currency Support | |||
Example: | |||
from frappe.integration_broker.doctype.integration_service.integration_service import get_integration_controller | |||
controller = get_integration_controller("PayPal") | |||
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": "USD" | |||
} | |||
# 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): | |||
# your code to handle callback | |||
##### Note: | |||
payment_status - payment gateway will put payment status on callback. | |||
For paypal payment status parameter is one from: [Completed, Cancelled, Failed] | |||
More Details: | |||
<div class="small">For details on how to get your API credentials, follow this link: <a href="https://developer.paypal.com/docs/classic/api/apiCredentials/" target="_blank">https://developer.paypal.com/docs/classic/api/apiCredentials/</a></div> | |||
""" | |||
class PayPalSettings(IntegrationService): | |||
service_name = "PayPal" | |||
supported_currencies = ["AUD", "BRL", "CAD", "CZK", "DKK", "EUR", "HKD", "HUF", "ILS", "JPY", "MYR", "MXN", | |||
"TWD", "NZD", "NOK", "PHP", "PLN", "GBP", "RUB", "SGD", "SEK", "CHF", "THB", "TRY", "USD"] | |||
def validate(self): | |||
if not self.flags.ignore_mandatory: | |||
self.validate_paypal_credentails() | |||
def on_update(self): | |||
pass | |||
def enable(self): | |||
call_hook_method('payment_gateway_enabled', gateway=self.service_name) | |||
if not self.flags.ignore_mandatory: | |||
self.validate_paypal_credentails() | |||
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_paypal_params_and_url(self): | |||
params = { | |||
"USER": self.api_username, | |||
"PWD": self.get_password(fieldname="api_password", raise_exception=False), | |||
"SIGNATURE": self.signature, | |||
"VERSION": "98", | |||
"METHOD": "GetPalDetails" | |||
} | |||
api_url = "https://api-3t.sandbox.paypal.com/nvp" if self.paypal_sandbox else "https://api-3t.paypal.com/nvp" | |||
return params, api_url | |||
def validate_paypal_credentails(self): | |||
params, url = self.get_paypal_params_and_url() | |||
params = urlencode(params) | |||
try: | |||
res = self.post_request(url=url, data=params.encode("utf-8")) | |||
if res["ACK"][0] == "Failure": | |||
raise Exception | |||
except Exception: | |||
frappe.throw(_("Invalid payment gateway credentials")) | |||
def get_payment_url(self, **kwargs): | |||
response = self.execute_set_express_checkout(kwargs["amount"], kwargs["currency"]) | |||
if self.paypal_sandbox: | |||
return_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}" | |||
else: | |||
return_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}" | |||
kwargs.update({ | |||
"token": response.get("TOKEN")[0], | |||
"correlation_id": response.get("CORRELATIONID")[0] | |||
}) | |||
self.integration_request = self.create_request(kwargs, "Remote", self.service_name, response.get("TOKEN")[0]) | |||
return return_url.format(kwargs["token"]) | |||
def execute_set_express_checkout(self, amount, currency): | |||
params, url = self.get_paypal_params_and_url() | |||
params.update({ | |||
"METHOD": "SetExpressCheckout", | |||
"PAYMENTREQUEST_0_PAYMENTACTION": "SALE", | |||
"PAYMENTREQUEST_0_AMT": amount, | |||
"PAYMENTREQUEST_0_CURRENCYCODE": currency.upper(), | |||
"returnUrl": get_url("/api/method/frappe.integrations.paypal.get_express_checkout_details"), | |||
"cancelUrl": get_url("/payment-cancel") | |||
}) | |||
params = urlencode(params) | |||
response = self.post_request(url, data=params.encode("utf-8")) | |||
if response.get("ACK")[0] != "Success": | |||
frappe.throw("Looks like something is wrong with this site's Paypal configuration.") | |||
return response | |||
@frappe.whitelist() | |||
def get_service_details(): | |||
return """ | |||
<div> | |||
<p> Steps to configure Service | |||
<ol> | |||
<li> Get PayPal api credentials from link: | |||
<a href="https://developer.paypal.com/docs/classic/api/apiCredentials/" target="_blank"> | |||
https://developer.paypal.com/docs/classic/api/apiCredentials/ | |||
</a> | |||
</li> | |||
<br> | |||
<li> Setup credentials on PayPal settings doctype. | |||
Click on | |||
<button class="btn btn-default btn-xs disabled"> PayPal Settings </button> | |||
top right corner | |||
</li> | |||
<br> | |||
<li> | |||
After saving settings, | |||
<label> | |||
<span class="input-area"> | |||
<input type="checkbox" class="input-with-feedback" checked disabled> | |||
</span> | |||
<span class="label-area small">Enabled</span> | |||
</label> | |||
PayPal Integration Service and Save a document. | |||
</li> | |||
<br> | |||
<li> | |||
To view PayPal payment logs, | |||
<button class="btn btn-default btn-xs disabled"> Show Log </button> | |||
</li> | |||
</ol> | |||
</div> | |||
""" | |||
@frappe.whitelist(allow_guest=True, xss_safe=True) | |||
def get_express_checkout_details(token): | |||
doc = frappe.get_doc("PayPal Settings") | |||
params, url = doc.get_paypal_params_and_url() | |||
params.update({ | |||
"METHOD": "GetExpressCheckoutDetails", | |||
"TOKEN": token | |||
}) | |||
response = doc.post_request(url, data=params) | |||
if response.get("ACK")[0] != "Success": | |||
frappe.respond_as_web_page(_("Something went wrong"), | |||
_("Looks like something went wrong during the transaction. Since we haven't confirmed the payment, Paypal will automatically refund you this amount. If it doesn't, please send us an email and mention the Correlation ID: {0}.").format(response.get("CORRELATIONID", [None])[0]), | |||
success=False, | |||
http_status_code=frappe.ValidationError.http_status_code) | |||
return | |||
update_integration_request_status(token, { | |||
"payerid": response.get("PAYERID")[0], | |||
"payer_email": response.get("EMAIL")[0] | |||
}, "Authorized") | |||
frappe.local.response["type"] = "redirect" | |||
frappe.local.response["location"] = get_url( \ | |||
"/api/method/frappe.integrations.paypal.confirm_payment?token={0}".format(token)) | |||
@frappe.whitelist(allow_guest=True, xss_safe=True) | |||
def confirm_payment(token): | |||
redirect = True | |||
status_changed_to, redirect_to = None, None | |||
doc = frappe.get_doc("PayPal Settings") | |||
integration_request = frappe.get_doc("Integration Request", token) | |||
data = json.loads(integration_request.data) | |||
redirect_to = data.get('redirect_to') or None | |||
redirect_message = data.get('redirect_message') or None | |||
params, url = doc.get_paypal_params_and_url() | |||
params.update({ | |||
"METHOD": "DoExpressCheckoutPayment", | |||
"PAYERID": data.get("payerid"), | |||
"TOKEN": token, | |||
"PAYMENTREQUEST_0_PAYMENTACTION": "SALE", | |||
"PAYMENTREQUEST_0_AMT": data.get("amount"), | |||
"PAYMENTREQUEST_0_CURRENCYCODE": data.get("currency").upper() | |||
}) | |||
response = doc.post_request(url, data=params) | |||
if response.get("ACK")[0] == "Success": | |||
update_integration_request_status(token, { | |||
"transaction_id": response.get("PAYMENTINFO_0_TRANSACTIONID")[0], | |||
"correlation_id": response.get("CORRELATIONID")[0] | |||
}, "Completed") | |||
if data.get("reference_doctype") and data.get("reference_docname"): | |||
redirect_url = frappe.get_doc(data.get("reference_doctype"), data.get("reference_docname")).run_method("on_payment_authorized", "Completed") | |||
if not redirect_url: | |||
redirect_url = '/integrations/payment-success' | |||
else: | |||
redirect_url = "/integrations/payment-failed" | |||
if redirect_to: | |||
redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to}) | |||
if redirect_message: | |||
redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message}) | |||
# this is done so that functions called via hooks can update flags.redirect_to | |||
if redirect: | |||
frappe.local.response["type"] = "redirect" | |||
frappe.local.response["location"] = get_url(redirect_to) | |||
def update_integration_request_status(token, data, status, error=False): | |||
frappe.get_doc("Integration Request", token).update_status(data, status) | |||
@frappe.whitelist(allow_guest=True, xss_safe=True) | |||
def get_checkout_url(**kwargs): | |||
try: | |||
doc = frappe.get_doc("PayPal Settings") | |||
return doc.get_payment_url(**kwargs) | |||
except Exception: | |||
frappe.respond_as_web_page(_("Something went wrong"), | |||
_("Looks like something is wrong with this site's Paypal configuration. Don't worry! No payment has been made from your Paypal account."), | |||
success=False, | |||
http_status_code=frappe.ValidationError.http_status_code) |
@@ -0,0 +1,33 @@ | |||
// Copyright (c) 2016, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.provide("frappe.integration_service") | |||
frappe.ui.form.on('Razorpay Settings', { | |||
refresh: function(frm) { | |||
} | |||
}); | |||
frappe.integration_service.razorpay_settings = Class.extend({ | |||
init: function(frm) { | |||
}, | |||
get_scheduler_job_info: function() { | |||
return { | |||
"Execute on every few minits of interval": " Captures all authorised payments" | |||
} | |||
}, | |||
get_service_info: function(frm) { | |||
frappe.call({ | |||
method: "frappe.integrations.doctype.razorpay_settings.razorpay_settings.get_service_details", | |||
callback: function(r){ | |||
var integration_service_help = frm.fields_dict.integration_service_help.wrapper; | |||
$(integration_service_help).empty(); | |||
$(integration_service_help).append(r.message); | |||
} | |||
}) | |||
} | |||
}) |
@@ -0,0 +1,137 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"beta": 0, | |||
"creation": "2016-09-20 03:44:03.799402", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "System", | |||
"editable_grid": 1, | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "api_key", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "API Key", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "api_secret", | |||
"fieldtype": "Password", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "API Secret", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"description": "Mention transaction completion page URL", | |||
"fieldname": "redirect_to", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Redirect To", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 1, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-09-26 02:00:03.604912", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "Razorpay Settings", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 0, | |||
"role": "System Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 1, | |||
"read_only_onload": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,246 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.utils import get_url, call_hook_method | |||
from frappe import _ | |||
import urllib, json | |||
from frappe.integration_broker.doctype.integration_service.integration_service import IntegrationService | |||
""" | |||
# Integrating RazorPay | |||
### Validate Currency | |||
Example: | |||
from frappe.integration_broker.doctype.integration_service.integration_service import get_integration_controller | |||
controller = get_integration_controller("Razorpay") | |||
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" | |||
} | |||
# 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 | |||
""" | |||
class RazorpaySettings(IntegrationService): | |||
service_name = "Razorpay" | |||
supported_currencies = ["INR"] | |||
scheduled_jobs = [ | |||
{ | |||
"all": [ | |||
"frappe.integrations.razorpay.capture_payment" | |||
] | |||
} | |||
] | |||
def validate(self): | |||
if not self.flags.ignore_mandatory: | |||
self.validate_razorpay_credentails() | |||
def on_update(self): | |||
pass | |||
def enable(self): | |||
call_hook_method('payment_gateway_enabled', gateway='Razorpay') | |||
if not self.flags.ignore_mandatory: | |||
self.validate_razorpay_credentails() | |||
def validate_razorpay_credentails(self): | |||
if self.api_key and self.api_secret: | |||
try: | |||
self.get_request(url="https://api.razorpay.com/v1/payments", | |||
auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False))) | |||
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 create_request(self, data): | |||
self.data = frappe._dict(data) | |||
try: | |||
self.integration_request = super(RazorpaySettings, self).create_request(self.data, "Host", \ | |||
"Razorpay") | |||
return self.authorize_payment() | |||
except Exception: | |||
frappe.log_error(frappe.get_traceback()) | |||
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 user’s payment details are successfully authenticated by the bank. | |||
The money is deducted from the customer’s account, but will not be transferred to the merchant’s account | |||
until it is explicitly captured by merchant. | |||
""" | |||
settings = self.get_settings() | |||
data = json.loads(self.integration_request.data) | |||
redirect_to = data.get('notes', {}).get('redirect_to') or None | |||
redirect_message = data.get('notes', {}).get('redirect_message') or None | |||
try: | |||
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" | |||
else: | |||
frappe.log_error(str(resp), 'Razorpay Payment not authorized') | |||
except: | |||
frappe.log_error(frappe.get_traceback()) | |||
# failed | |||
pass | |||
status = frappe.flags.integration_request.status_code | |||
if self.flags.status_changed_to == "Authorized": | |||
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' | |||
else: | |||
redirect_url = 'payment-failed' | |||
if redirect_to: | |||
redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to}) | |||
if redirect_message: | |||
redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message}) | |||
return { | |||
"redirect_to": redirect_url, | |||
"status": status | |||
} | |||
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("Razorpay Settings") | |||
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=(controller.api_key, controller.get_password("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 frappe.get_doc("Razorpay Settings").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) | |||
@frappe.whitelist() | |||
def get_service_details(): | |||
return """ | |||
<div> | |||
<p> Steps to configure Service | |||
<ol> | |||
<li> Get Razorpay api credentials by login to: | |||
<a href="https://razorpay.com/" target="_blank"> | |||
https://razorpay.com/ | |||
</a> | |||
</li> | |||
<br> | |||
<li> Setup credentials on Razorpay Settings doctype. | |||
Click on | |||
<button class="btn btn-default btn-xs disabled"> Razorpay Settings </button> | |||
top right corner | |||
</li> | |||
<br> | |||
<li> | |||
After saving settings, | |||
<label> | |||
<span class="input-area"> | |||
<input type="checkbox" class="input-with-feedback" checked disabled> | |||
</span> | |||
<span class="label-area small">Enable</span> | |||
</label> | |||
Razorpay Integration Service and Save a document. | |||
</li> | |||
<br> | |||
<li> | |||
To view Razorpays payment logs, | |||
<button class="btn btn-default btn-xs disabled"> Show Log </button> | |||
</li> | |||
</ol> | |||
</div> | |||
""" |
@@ -6,8 +6,6 @@ from frappe import _ | |||
from frappe.utils import flt | |||
import json | |||
from frappe.integrations.razorpay import Controller | |||
no_cache = 1 | |||
no_sitemap = 1 | |||
@@ -16,7 +14,7 @@ expected_keys = ('amount', 'title', 'description', 'reference_doctype', 'referen | |||
def get_context(context): | |||
context.no_cache = 1 | |||
context.api_key = Controller().get_settings().api_key | |||
context.api_key = frappe.db.get_value("Razorpay Settings", None, "api_key") | |||
# all these keys exist in form_dict | |||
if not (set(expected_keys) - set(frappe.form_dict.keys())): | |||
@@ -43,4 +41,6 @@ def make_payment(razorpay_payment_id, options, reference_doctype, reference_docn | |||
"reference_doctype": reference_doctype | |||
}) | |||
return Controller().create_request(data) | |||
data = frappe.get_doc("Razorpay Settings").create_request(data) | |||
frappe.db.commit() | |||
return data |