@@ -1248,6 +1248,10 @@ def logger(module=None, with_more_info=True): | |||||
from frappe.utils.logger import get_logger | from frappe.utils.logger import get_logger | ||||
return get_logger(module or 'default', with_more_info=with_more_info) | return get_logger(module or 'default', with_more_info=with_more_info) | ||||
def log_error(message, title=None): | |||||
'''Log error to Scheduler Log''' | |||||
get_doc(dict(doctype='Scheduler Log', error=str(message), method=title)).insert() | |||||
def get_desk_link(doctype, name): | def get_desk_link(doctype, name): | ||||
return '<a href="#Form/{0}/{1}" style="font-weight: bold;">{2} {1}</a>'.format(doctype, name, _(doctype)) | return '<a href="#Form/{0}/{1}" style="font-weight: bold;">{2} {1}</a>'.format(doctype, name, _(doctype)) | ||||
@@ -10,7 +10,7 @@ from frappe.utils.background_jobs import enqueue, get_jobs | |||||
import json, urlparse | import json, urlparse | ||||
from frappe.utils import get_request_session | from frappe.utils import get_request_session | ||||
class IntegrationService(Document): | |||||
class IntegrationService(Document): | |||||
def on_update(self): | def on_update(self): | ||||
if self.enabled: | if self.enabled: | ||||
self.enable_service() | self.enable_service() | ||||
@@ -25,7 +25,7 @@ class IntegrationService(Document): | |||||
parameters = {} | parameters = {} | ||||
if self.custom_settings_json: | if self.custom_settings_json: | ||||
parameters = json.loads(self.custom_settings_json) | parameters = json.loads(self.custom_settings_json) | ||||
return parameters | |||||
return parameters | |||||
def install_fixtures(self): | def install_fixtures(self): | ||||
pass | pass | ||||
@@ -52,13 +52,13 @@ class IntegrationService(Document): | |||||
try: | try: | ||||
s = get_request_session() | s = get_request_session() | ||||
res = s.get(url, data={}, auth=auth) | |||||
res.raise_for_status() | |||||
return res.json() | |||||
frappe.flags.integration_request = s.get(url, data={}, auth=auth) | |||||
frappe.flags.integration_request.raise_for_status() | |||||
return frappe.flags.integration_request.json() | |||||
except Exception, exc: | except Exception, exc: | ||||
raise exc | raise exc | ||||
def post_request(self, url, auth=None, data=None): | def post_request(self, url, auth=None, data=None): | ||||
if not auth: | if not auth: | ||||
auth = '' | auth = '' | ||||
@@ -68,31 +68,31 @@ class IntegrationService(Document): | |||||
s = get_request_session() | s = get_request_session() | ||||
res = s.post(url, data=data, auth=auth) | res = s.post(url, data=data, auth=auth) | ||||
res.raise_for_status() | res.raise_for_status() | ||||
if res.headers.get("content-type") == "text/plain; charset=utf-8": | if res.headers.get("content-type") == "text/plain; charset=utf-8": | ||||
return urlparse.parse_qs(res.text) | return urlparse.parse_qs(res.text) | ||||
return res.json() | return res.json() | ||||
except Exception, exc: | except Exception, exc: | ||||
raise exc | raise exc | ||||
def put_request(url, auth=None, data=None): | def put_request(url, auth=None, data=None): | ||||
pass | pass | ||||
def create_request(self, data, integration_type, service_name, name=None): | def create_request(self, data, integration_type, service_name, name=None): | ||||
if not isinstance(data, basestring): | if not isinstance(data, basestring): | ||||
data = json.dumps(data) | data = json.dumps(data) | ||||
integration_request = frappe.get_doc({ | integration_request = frappe.get_doc({ | ||||
"doctype": "Integration Request", | "doctype": "Integration Request", | ||||
"integration_type": integration_type, | "integration_type": integration_type, | ||||
"integration_request_service": service_name, | "integration_request_service": service_name, | ||||
"data": data | "data": data | ||||
}) | }) | ||||
if name: | if name: | ||||
integration_request.flags._name = name | integration_request.flags._name = name | ||||
integration_request.insert(ignore_permissions=True) | integration_request.insert(ignore_permissions=True) | ||||
frappe.db.commit() | frappe.db.commit() | ||||
@@ -111,7 +111,7 @@ def get_js_resouce(service): | |||||
return { | return { | ||||
"js": getattr(controller, "js", "") | "js": getattr(controller, "js", "") | ||||
} | } | ||||
def get_integration_controller(service_name, setup=True): | def get_integration_controller(service_name, setup=True): | ||||
'''Returns integration controller module from app_name.integrations.{service}''' | '''Returns integration controller module from app_name.integrations.{service}''' | ||||
def load_from_app(app, service_name): | def load_from_app(app, service_name): | ||||
@@ -126,12 +126,12 @@ def get_integration_controller(service_name, setup=True): | |||||
for d in getattr(controller, key, []): | for d in getattr(controller, key, []): | ||||
tmp.append(frappe._dict(d)) | tmp.append(frappe._dict(d)) | ||||
setattr(controller, key, tmp) | setattr(controller, key, tmp) | ||||
return controller | return controller | ||||
except ImportError: | except ImportError: | ||||
pass | pass | ||||
for app in frappe.get_installed_apps(): | for app in frappe.get_installed_apps(): | ||||
controller = load_from_app(app, service_name) | controller = load_from_app(app, service_name) | ||||
if controller: | if controller: | ||||
@@ -144,13 +144,13 @@ def get_integration_services(): | |||||
services = [""] | services = [""] | ||||
for app in frappe.get_installed_apps(): | for app in frappe.get_installed_apps(): | ||||
services.extend(frappe.get_hooks("integration_services", app_name = app)) | services.extend(frappe.get_hooks("integration_services", app_name = app)) | ||||
return services | return services | ||||
def trigger_integration_service_events(): | def trigger_integration_service_events(): | ||||
for service in frappe.get_all("Integration Service", filters={"enabled": 1}, fields=["name"]): | for service in frappe.get_all("Integration Service", filters={"enabled": 1}, fields=["name"]): | ||||
controller = get_integration_controller(service.name, setup=False) | controller = get_integration_controller(service.name, setup=False) | ||||
if hasattr(controller, "scheduled_jobs"): | if hasattr(controller, "scheduled_jobs"): | ||||
for job in controller.scheduled_jobs: | for job in controller.scheduled_jobs: | ||||
for event, handlers in job.items(): | for event, handlers in job.items(): | ||||
@@ -127,6 +127,7 @@ class Controller(IntegrationController): | |||||
return self.authorize_payment() | return self.authorize_payment() | ||||
except Exception: | except Exception: | ||||
frappe.log_error(frappe.get_traceback()) | |||||
return{ | 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.")), | "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 | "status": 401 | ||||
@@ -141,28 +142,45 @@ class Controller(IntegrationController): | |||||
settings = self.get_settings() | settings = self.get_settings() | ||||
data = json.loads(self.integration_request.data) | 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 | |||||
if self.integration_request.status != "Authorized": | 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)) | |||||
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" | |||||
except: | |||||
frappe.log_error(frappe.get_traceback()) | |||||
# failed | |||||
pass | |||||
if resp.get("status") == "authorized": | |||||
self.integration_request.db_set('status', 'Authorized', update_modified=False) | |||||
self.flags.status_changed_to = "Authorized" | |||||
status = frappe.flags.integration_request.status_code | |||||
if self.flags.status_changed_to == "Authorized": | if self.flags.status_changed_to == "Authorized": | ||||
if self.data.reference_doctype and self.data.reference_docname: | if self.data.reference_doctype and self.data.reference_docname: | ||||
redirect_to = frappe.get_doc(self.data.reference_doctype, | |||||
custom_redirect_to = frappe.get_doc(self.data.reference_doctype, | |||||
self.data.reference_docname).run_method("on_payment_authorized", self.flags.status_changed_to) | self.data.reference_docname).run_method("on_payment_authorized", self.flags.status_changed_to) | ||||
if not redirect_to: | |||||
if data.get('redirect_to'): | |||||
redirect_to = data.get('redirect_to') | |||||
if custom_redirect_to: | |||||
redirect_to = custom_redirect_to | |||||
return { | |||||
"redirect_to": redirect_to or "payment-success", | |||||
"status": 200 | |||||
} | |||||
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): | def capture_payment(is_sandbox=False, sanbox_response=None): | ||||
""" | """ | ||||
@@ -5,7 +5,6 @@ $(document).ready(function(){ | |||||
"amount": cint({{ amount }} * 100), // 2000 paise = INR 20 | "amount": cint({{ amount }} * 100), // 2000 paise = INR 20 | ||||
"name": "{{ title }}", | "name": "{{ title }}", | ||||
"description": "{{ description }}", | "description": "{{ description }}", | ||||
"image": "{{ brand_image }}", | |||||
"handler": function (response){ | "handler": function (response){ | ||||
razorpay.make_payment_log(response, options, "{{ reference_doctype }}", "{{ reference_docname }}"); | razorpay.make_payment_log(response, options, "{{ reference_doctype }}", "{{ reference_docname }}"); | ||||
}, | }, | ||||
@@ -14,14 +13,7 @@ $(document).ready(function(){ | |||||
"email": "{{ payer_email }}", | "email": "{{ payer_email }}", | ||||
"order_id": "{{ order_id }}" | "order_id": "{{ order_id }}" | ||||
}, | }, | ||||
"notes": { | |||||
"doctype": "{{ doctype }}", | |||||
"name": "{{ name }}", | |||||
"payment_request": "{{ name }}" // backward compatibility | |||||
}, | |||||
"theme": { | |||||
"color": "#4B4C9D" | |||||
} | |||||
"notes": {{ frappe.form_dict|json }} | |||||
}; | }; | ||||
var rzp = new Razorpay(options); | var rzp = new Razorpay(options); | ||||
@@ -1,12 +1,12 @@ | |||||
{% extends "templates/web.html" %} | {% extends "templates/web.html" %} | ||||
{% block title %}Make Payment{% endblock %} | |||||
{% block title %}{{ _("Payment Cancelled") }}{% endblock %} | |||||
{%- block header -%} | {%- block header -%} | ||||
<h2>Payment Cancelled<h2> | |||||
<h2>{{ _("Payment Cancelled") }}<h2> | |||||
{% endblock %} | {% endblock %} | ||||
{%- block page_content -%} | {%- block page_content -%} | ||||
<p>You have cancelled your payment.</p> | |||||
<p>{{ _("You have cancelled the payment") }}</p> | |||||
<p><br><a href="/">Back to home page</a></p> | <p><br><a href="/">Back to home page</a></p> | ||||
{% endblock %} | {% endblock %} |
@@ -1,12 +1,12 @@ | |||||
{% extends "templates/web.html" %} | {% extends "templates/web.html" %} | ||||
{% block title %}Payment Failed{% endblock %} | |||||
{% block title %}{{ _("Payment Failed") }}{% endblock %} | |||||
{%- block header -%} | {%- block header -%} | ||||
<h2>Payment Failed<h2> | |||||
<h2>{{ _("Payment Failed") }}<h2> | |||||
{% endblock %} | {% endblock %} | ||||
{%- block page_content -%} | {%- block page_content -%} | ||||
<p class="lead">Your payment has failed. Do you mind trying again?</p> | |||||
<p><a href="/" class="btn btn-default">Back to Home</a></p> | |||||
<p class="lead">{{ _("Oops. Your payment has failed.") }}</p> | |||||
<p><a href="{{ frappe.form_dict.redirect_to or "/" }}" class="btn btn-primary">{{ frappe.form_dict.redirect_message or _("Continue") }}</a></p> | |||||
{% endblock %} | {% endblock %} |
@@ -1,12 +1,13 @@ | |||||
{% extends "templates/web.html" %} | {% extends "templates/web.html" %} | ||||
{% block title %}Payment Success{% endblock %} | |||||
{% block title %}{{ _("Payment Success") }}{% endblock %} | |||||
{%- block header -%} | {%- block header -%} | ||||
<h2>Payment Success<h2> | |||||
<h2>{{ _("Payment Success") }}<h2> | |||||
{% endblock %} | {% endblock %} | ||||
{%- block page_content -%} | {%- block page_content -%} | ||||
<p class="lead">Your payment has succeeded.</p> | |||||
<p><a href="/" class="btn btn-default">Back to Home</a></p> | |||||
<p class="lead">{{ _("Your payment was successfully accepted") }}</p> | |||||
<p><a href="{{ frappe.form_dict.redirect_to or "/" }}" | |||||
class="btn btn-primary">{{ frappe.form_dict.redirect_message or _("Continue") }}</a></p> | |||||
{% endblock %} | {% endblock %} |
@@ -17,13 +17,8 @@ expected_keys = ('amount', 'title', 'description', 'reference_doctype', 'referen | |||||
def get_context(context): | def get_context(context): | ||||
context.no_cache = 1 | context.no_cache = 1 | ||||
context.api_key = Controller().get_settings().api_key | context.api_key = Controller().get_settings().api_key | ||||
installed_apps = frappe.get_installed_apps() | installed_apps = frappe.get_installed_apps() | ||||
if 'erpnext' in installed_apps: | |||||
context.brand_image = "/assets/erpnext/images/erp-icon.svg" | |||||
else: | |||||
context.brand_image = '/assets/frappe_theme/img/erp-icon.svg' | |||||
# all these keys exist in form_dict | # all these keys exist in form_dict | ||||
if not (set(expected_keys) - set(frappe.form_dict.keys())): | if not (set(expected_keys) - set(frappe.form_dict.keys())): | ||||
@@ -40,14 +35,14 @@ def get_context(context): | |||||
@frappe.whitelist(allow_guest=True) | @frappe.whitelist(allow_guest=True) | ||||
def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname): | def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname): | ||||
data = {} | data = {} | ||||
if isinstance(options, basestring): | if isinstance(options, basestring): | ||||
data = json.loads(options) | data = json.loads(options) | ||||
data.update({ | data.update({ | ||||
"razorpay_payment_id": razorpay_payment_id, | "razorpay_payment_id": razorpay_payment_id, | ||||
"reference_docname": reference_docname, | "reference_docname": reference_docname, | ||||
"reference_doctype": reference_doctype | "reference_doctype": reference_doctype | ||||
}) | }) | ||||
return Controller().create_request(data) | return Controller().create_request(data) |