@@ -0,0 +1,8 @@ | |||
// Copyright (c) 2017, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.ui.form.on('Stripe Settings', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -0,0 +1,120 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_guest_to_view": 0, | |||
"allow_import": 0, | |||
"allow_rename": 0, | |||
"beta": 0, | |||
"creation": "2017-03-09 17:18:29.458397", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "", | |||
"editable_grid": 1, | |||
"engine": "InnoDB", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"columns": 0, | |||
"fieldname": "publishable_key", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Publishable Key", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 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": "secret_key", | |||
"fieldtype": "Password", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_standard_filter": 0, | |||
"label": "Secret Key", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"remember_last_selected_value": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"has_web_view": 0, | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"is_submittable": 0, | |||
"issingle": 1, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-03-09 17:19:25.087475", | |||
"modified_by": "Administrator", | |||
"module": "Integrations", | |||
"name": "Stripe Settings", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 0, | |||
"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": 1, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"show_name_in_global_search": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_changes": 0, | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,115 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2017, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
from frappe import _ | |||
import urllib | |||
from frappe.utils import get_url, call_hook_method, cint | |||
from frappe.integrations.utils import make_get_request, make_post_request, create_request_log, create_payment_gateway | |||
class StripeSettings(Document): | |||
supported_currencies = [ | |||
"AED", "ALL", "ANG", "ARS", "AUD", "AWG", "BBD", "BDT", "BIF", "BMD", "BND", | |||
"BOB", "BRL", "BSD", "BWP", "BZD", "CAD", "CHF", "CLP", "CNY", "COP", "CRC", "CVE", "CZK", "DJF", | |||
"DKK", "DOP", "DZD", "EGP", "ETB", "EUR", "FJD", "FKP", "GBP", "GIP", "GMD", "GNF", "GTQ", "GYD", | |||
"HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "ISK", "JMD", "JPY", "KES", "KHR", "KMF", | |||
"KRW", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "MAD", "MDL", "MNT", "MOP", "MRO", "MUR", "MVR", | |||
"MWK", "MXN", "MYR", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "PAB", "PEN", "PGK", "PHP", "PKR", | |||
"PLN", "PYG", "QAR", "RUB", "SAR", "SBD", "SCR", "SEK", "SGD", "SHP", "SLL", "SOS", "STD", "SVC", | |||
"SZL", "THB", "TOP", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VND", "VUV", "WST", | |||
"XAF", "XOF", "XPF", "YER", "ZAR" | |||
] | |||
def validate(self): | |||
create_payment_gateway('Stripe') | |||
call_hook_method('payment_gateway_enabled', gateway='Stripe') | |||
if not self.flags.ignore_mandatory: | |||
self.validate_stripe_credentails() | |||
def validate_stripe_credentails(self): | |||
if self.publishable_key and self.secret_key: | |||
header = {"Authorization": "Bearer {0}".format(self.get_password(fieldname="secret_key", raise_exception=False))} | |||
try: | |||
make_get_request(url="https://api.stripe.com/v1/charges", headers=header) | |||
except Exception: | |||
frappe.throw(_("Seems Publishable Key or Secret Key is wrong !!!")) | |||
def validate_transaction_currency(self, currency): | |||
if currency not in self.supported_currencies: | |||
frappe.throw(_("Please select another payment method. Stripe does not support transactions in currency '{0}'").format(currency)) | |||
def get_payment_url(self, **kwargs): | |||
return get_url("./integrations/stripe_checkout?{0}".format(urllib.urlencode(kwargs))) | |||
def create_request(self, data): | |||
self.data = frappe._dict(data) | |||
try: | |||
self.integration_request = create_request_log(self.data, "Host", "Stripe") | |||
return self.create_charge_on_stripe() | |||
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 create_charge_on_stripe(self): | |||
headers = {"Authorization": | |||
"Bearer {0}".format(self.get_password(fieldname="secret_key", raise_exception=False))} | |||
data = { | |||
"amount": cint(self.data.amount)*100, | |||
"currency": self.data.currency, | |||
"source": self.data.stripe_token_id, | |||
"description": self.data.description | |||
} | |||
redirect_to = self.data.get('redirect_to') or None | |||
redirect_message = self.data.get('redirect_message') or None | |||
try: | |||
resp = make_post_request(url="https://api.stripe.com/v1/charges", headers=headers, data=data) | |||
if resp.get("captured") == True: | |||
self.integration_request.db_set('status', 'Completed', update_modified=False) | |||
self.flags.status_changed_to = "Completed" | |||
else: | |||
frappe.log_error(str(resp), 'Stripe Payment not completed') | |||
except: | |||
frappe.log_error(frappe.get_traceback()) | |||
# failed | |||
pass | |||
status = frappe.flags.integration_request.status_code | |||
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' | |||
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 | |||
} |
@@ -0,0 +1,47 @@ | |||
$(document).ready(function(){ | |||
(function(e){ | |||
var handler = StripeCheckout.configure({ | |||
key: "{{ publishable_key }}", | |||
token: function(token) { | |||
// You can access the token ID with `token.id`. | |||
// Get the token ID to your server-side code for use. | |||
stripe.make_payment_log(token, {{ frappe.form_dict|json }}, "{{ reference_doctype }}", "{{ reference_docname }}"); | |||
} | |||
}); | |||
handler.open({ | |||
name: "{{payer_name}}", | |||
description: "{{description}}", | |||
amount: cint("{{ amount }}" * 100), // 2000 paise = INR 20 | |||
email: "{{payer_email}}", | |||
currency: "{{currency}}" | |||
}); | |||
})(); | |||
}) | |||
frappe.provide('stripe'); | |||
stripe.make_payment_log = function(token, data, doctype, docname){ | |||
$('.stripe-loading').addClass('hidden'); | |||
$('.stripe-confirming').removeClass('hidden'); | |||
frappe.call({ | |||
method:"frappe.templates.pages.integrations.stripe_checkout.make_payment", | |||
freeze:true, | |||
headers: {"X-Requested-With": "XMLHttpRequest"}, | |||
args: { | |||
"stripe_token_id": token.id, | |||
"data": JSON.stringify(data), | |||
"reference_doctype": doctype, | |||
"reference_docname": docname | |||
}, | |||
callback: function(r){ | |||
if (r.message && r.message.status == 200) { | |||
window.location.href = r.message.redirect_to | |||
} | |||
else if (r.message && ([401,400,500].indexOf(r.message.status) > -1)) { | |||
window.location.href = r.message.redirect_to | |||
} | |||
} | |||
}) | |||
} |
@@ -0,0 +1,28 @@ | |||
{% extends "templates/web.html" %} | |||
{% block title %} Payment {% endblock %} | |||
{%- block header -%}{% endblock %} | |||
{% block script %} | |||
<script src="https://checkout.stripe.com/checkout.js"></script> | |||
<script>{% include "templates/includes/integrations/stripe_checkout.js" %}</script> | |||
{% endblock %} | |||
{%- block page_content -%} | |||
<p class='lead text-center centered'> | |||
<span class='stripe-loading'>Loading Payment System</span> | |||
<span class='stripe-confirming hidden'>Confirming Payment</span> | |||
</p> | |||
{% endblock %} | |||
{% block style %} | |||
<style> | |||
header, footer { | |||
display: none; | |||
} | |||
</style> | |||
{% endblock %} |
@@ -0,0 +1,49 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# License: GNU General Public License v3. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe import _ | |||
from frappe.utils import flt, cint | |||
import json | |||
no_cache = 1 | |||
no_sitemap = 1 | |||
expected_keys = ('amount', 'title', 'description', 'reference_doctype', 'reference_docname', | |||
'payer_name', 'payer_email', 'order_id', 'currency') | |||
def get_context(context): | |||
context.no_cache = 1 | |||
context.publishable_key = get_api_key() | |||
# all these keys exist in form_dict | |||
if not (set(expected_keys) - set(frappe.form_dict.keys())): | |||
for key in expected_keys: | |||
context[key] = frappe.form_dict[key] | |||
context['amount'] = flt(context['amount']) | |||
else: | |||
frappe.redirect_to_message(_('Some information is missing'), | |||
_('Looks like someone sent you to an incomplete URL. Please ask them to look into it.')) | |||
frappe.local.flags.redirect_location = frappe.local.response.location | |||
raise frappe.Redirect | |||
def get_api_key(): | |||
publishable_key = frappe.db.get_value("Stripe Settings", None, "publishable_key") | |||
if cint(frappe.form_dict.get("use_sandbox")): | |||
publishable_key = frappe.conf.sandbox_publishable_key | |||
return publishable_key | |||
@frappe.whitelist(allow_guest=True) | |||
def make_payment(stripe_token_id, data, reference_doctype=None, reference_docname=None): | |||
data = json.loads(data) | |||
data.update({ | |||
"stripe_token_id": stripe_token_id | |||
}) | |||
data = frappe.get_doc("Stripe Settings").create_request(data) | |||
frappe.db.commit() | |||
return data |