* Braintree Integration WIP * Braintree integration * Link in config + settings after save * Code cleanup * Code cleanup * JS beautify issue * Codacy corrections * Spaces to tabspull/2/head
@@ -0,0 +1,6 @@ | |||||
// Copyright (c) 2018, Frappe Technologies and contributors | |||||
// For license information, please see license.txt | |||||
frappe.ui.form.on('Braintree Settings', { | |||||
}); |
@@ -0,0 +1,273 @@ | |||||
{ | |||||
"allow_copy": 0, | |||||
"allow_guest_to_view": 0, | |||||
"allow_import": 0, | |||||
"allow_rename": 0, | |||||
"autoname": "field:gateway_name", | |||||
"beta": 0, | |||||
"creation": "2018-02-05 13:46:12.101852", | |||||
"custom": 0, | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "", | |||||
"editable_grid": 1, | |||||
"engine": "InnoDB", | |||||
"fields": [ | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "gateway_name", | |||||
"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": "Payment Gateway Name", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "Company", | |||||
"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_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "section_break_2", | |||||
"fieldtype": "Section Break", | |||||
"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, | |||||
"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": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "merchant_id", | |||||
"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": "Merchant ID", | |||||
"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_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "public_key", | |||||
"fieldtype": "Data", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 1, | |||||
"in_standard_filter": 0, | |||||
"label": "Public 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_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "private_key", | |||||
"fieldtype": "Password", | |||||
"hidden": 0, | |||||
"ignore_user_permissions": 0, | |||||
"ignore_xss_filter": 0, | |||||
"in_filter": 0, | |||||
"in_global_search": 0, | |||||
"in_list_view": 1, | |||||
"in_standard_filter": 0, | |||||
"label": "Private 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_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "use_sandbox", | |||||
"fieldtype": "Check", | |||||
"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": "Use Sandbox", | |||||
"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": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "header_img", | |||||
"fieldtype": "Attach Image", | |||||
"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": "Header Image", | |||||
"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": 0, | |||||
"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": 0, | |||||
"istable": 0, | |||||
"max_attachments": 0, | |||||
"modified": "2018-02-05 14:33:06.050377", | |||||
"modified_by": "Administrator", | |||||
"module": "Integrations", | |||||
"name": "Braintree 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,136 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2018, Frappe Technologies and contributors | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
from frappe.model.document import Document | |||||
import braintree | |||||
from frappe import _ | |||||
from six.moves.urllib.parse import urlencode | |||||
from frappe.utils import get_url, call_hook_method | |||||
from frappe.integrations.utils import create_request_log, create_payment_gateway | |||||
class BraintreeSettings(Document): | |||||
supported_currencies = [ | |||||
"AED","AMD","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BGN","BIF","BMD","BND","BOB", | |||||
"BRL","BSD","BWP","BYN","BZD","CAD","CHF","CLP","CNY","COP","CRC","CVE","CZK","DJF","DKK", | |||||
"DOP","DZD","EGP","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD", | |||||
"HKD","HNL","HRK","HTG","HUF","IDR","ILS","INR","ISK","JMD","JPY","KES","KGS","KHR","KMF", | |||||
"KRW","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LTL","MAD","MDL","MKD","MNT","MOP","MUR", | |||||
"MVR","MWK","MXN","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","PAB","PEN","PGK","PHP", | |||||
"PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SEK","SGD","SHP","SLL", | |||||
"SOS","SRD","STD","SVC","SYP","SZL","THB","TJS","TOP","TRY","TTD","TWD","TZS","UAH","UGX", | |||||
"USD","UYU","UZS","VEF","VND","VUV","WST","XAF","XCD","XOF","XPF","YER","ZAR","ZMK","ZWD" | |||||
] | |||||
def validate(self): | |||||
if not self.flags.ignore_mandatory: | |||||
self.configure_braintree() | |||||
def on_update(self): | |||||
create_payment_gateway('Braintree-' + self.gateway_name, settings='Braintree Settings', controller=self.gateway_name) | |||||
call_hook_method('payment_gateway_enabled', gateway='Braintree-' + self.gateway_name) | |||||
def configure_braintree(self): | |||||
if self.use_sandbox: | |||||
environment = 'sandbox' | |||||
else: | |||||
environment = 'production' | |||||
braintree.Configuration.configure( | |||||
environment=environment, | |||||
merchant_id=self.merchant_id, | |||||
public_key=self.public_key, | |||||
private_key=self.get_password(fieldname='private_key',raise_exception=False) | |||||
) | |||||
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/braintree_checkout?{0}".format(urlencode(kwargs))) | |||||
def create_payment_request(self, data): | |||||
self.data = frappe._dict(data) | |||||
try: | |||||
self.integration_request = create_request_log(self.data, "Host", "Braintree") | |||||
return self.create_charge_on_braintree() | |||||
except Exception: | |||||
frappe.log_error(frappe.get_traceback()) | |||||
return{ | |||||
"redirect_to": frappe.redirect_to_message(_('Server Error'), _("There seems to be an issue with the server's braintree configuration. Don't worry, in case of failure, the amount will get refunded to your account.")), | |||||
"status": 401 | |||||
} | |||||
def create_charge_on_braintree(self): | |||||
self.configure_braintree() | |||||
redirect_to = self.data.get('redirect_to') or None | |||||
redirect_message = self.data.get('redirect_message') or None | |||||
result = braintree.Transaction.sale({ | |||||
"amount": self.data.amount, | |||||
"payment_method_nonce": self.data.payload_nonce, | |||||
"options": { | |||||
"submit_for_settlement": True | |||||
} | |||||
}) | |||||
if result.is_success: | |||||
self.integration_request.db_set('status', 'Completed', update_modified=False) | |||||
self.flags.status_changed_to = "Completed" | |||||
self.integration_request.db_set('output', result.transaction.status, update_modified=False) | |||||
elif result.transaction: | |||||
self.integration_request.db_set('status', 'Failed', update_modified=False) | |||||
error_log = frappe.log_error("code: " + str(result.transaction.processor_response_code) + " | text: " + str(result.transaction.processor_response_text), "Braintree Payment Error") | |||||
self.integration_request.db_set('error', error_log.error, update_modified=False) | |||||
else: | |||||
self.integration_request.db_set('status', 'Failed', update_modified=False) | |||||
for error in result.errors.deep_errors: | |||||
error_log = frappe.log_error("code: " + str(error.code) + " | message: " + str(error.message), "Braintree Payment Error") | |||||
self.integration_request.db_set('error', error_log.error, update_modified=False) | |||||
if self.flags.status_changed_to == "Completed": | |||||
status = '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: | |||||
status = 'Error' | |||||
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 get_gateway_controller(doc): | |||||
payment_request = frappe.get_doc("Payment Request", doc) | |||||
gateway_controller = frappe.db.get_value("Payment Gateway", payment_request.payment_gateway, "gateway_controller") | |||||
return gateway_controller | |||||
def get_client_token(doc): | |||||
gateway_controller = get_gateway_controller(doc) | |||||
settings = frappe.get_doc("Braintree Settings", gateway_controller) | |||||
settings.configure_braintree() | |||||
return braintree.ClientToken.generate() |
@@ -0,0 +1,23 @@ | |||||
/* eslint-disable */ | |||||
// rename this file from _test_[name] to test_[name] to activate | |||||
// and remove above this line | |||||
QUnit.test("test: Braintree Settings", function (assert) { | |||||
let done = assert.async(); | |||||
// number of asserts | |||||
assert.expect(1); | |||||
frappe.run_serially([ | |||||
// insert a new Braintree Setting | |||||
() => frappe.tests.make('Braintree Settings', [ | |||||
// values to be set | |||||
{key: 'value'} | |||||
]), | |||||
() => { | |||||
assert.equal(cur_frm.doc.key, 'value'); | |||||
}, | |||||
() => done() | |||||
]); | |||||
}); |
@@ -0,0 +1,9 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Copyright (c) 2018, Frappe Technologies and Contributors | |||||
# See license.txt | |||||
from __future__ import unicode_literals | |||||
import unittest | |||||
class TestBraintreeSettings(unittest.TestCase): | |||||
pass |
@@ -13,6 +13,7 @@ | |||||
"editable_grid": 1, | "editable_grid": 1, | ||||
"fields": [ | "fields": [ | ||||
{ | { | ||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | "allow_on_submit": 0, | ||||
"bold": 0, | "bold": 0, | ||||
"collapsible": 0, | "collapsible": 0, | ||||
@@ -24,7 +25,7 @@ | |||||
"ignore_xss_filter": 0, | "ignore_xss_filter": 0, | ||||
"in_filter": 0, | "in_filter": 0, | ||||
"in_global_search": 0, | "in_global_search": 0, | ||||
"in_list_view": 0, | |||||
"in_list_view": 1, | |||||
"in_standard_filter": 0, | "in_standard_filter": 0, | ||||
"label": "Gateway", | "label": "Gateway", | ||||
"length": 0, | "length": 0, | ||||
@@ -40,6 +41,68 @@ | |||||
"search_index": 0, | "search_index": 0, | ||||
"set_only_once": 0, | "set_only_once": 0, | ||||
"unique": 0 | "unique": 0 | ||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "gateway_settings", | |||||
"fieldtype": "Link", | |||||
"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": "Gateway Settings", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "DocType", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
}, | |||||
{ | |||||
"allow_bulk_edit": 0, | |||||
"allow_on_submit": 0, | |||||
"bold": 0, | |||||
"collapsible": 0, | |||||
"columns": 0, | |||||
"fieldname": "gateway_controller", | |||||
"fieldtype": "Dynamic Link", | |||||
"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": "Gateway Controller", | |||||
"length": 0, | |||||
"no_copy": 0, | |||||
"options": "gateway_settings", | |||||
"permlevel": 0, | |||||
"precision": "", | |||||
"print_hide": 0, | |||||
"print_hide_if_no_value": 0, | |||||
"read_only": 0, | |||||
"remember_last_selected_value": 0, | |||||
"report_hide": 0, | |||||
"reqd": 0, | |||||
"search_index": 0, | |||||
"set_only_once": 0, | |||||
"unique": 0 | |||||
} | } | ||||
], | ], | ||||
"has_web_view": 0, | "has_web_view": 0, | ||||
@@ -52,7 +115,7 @@ | |||||
"issingle": 0, | "issingle": 0, | ||||
"istable": 0, | "istable": 0, | ||||
"max_attachments": 0, | "max_attachments": 0, | ||||
"modified": "2017-03-09 12:40:56.176464", | |||||
"modified": "2018-02-05 14:24:33.526645", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Core", | "module": "Core", | ||||
"name": "Payment Gateway", | "name": "Payment Gateway", | ||||
@@ -0,0 +1,23 @@ | |||||
/* eslint-disable */ | |||||
// rename this file from _test_[name] to test_[name] to activate | |||||
// and remove above this line | |||||
QUnit.test("test: Payment Gateway", function (assert) { | |||||
let done = assert.async(); | |||||
// number of asserts | |||||
assert.expect(1); | |||||
frappe.run_serially([ | |||||
// insert a new Payment Gateway | |||||
() => frappe.tests.make('Payment Gateway', [ | |||||
// values to be set | |||||
{key: 'value'} | |||||
]), | |||||
() => { | |||||
assert.equal(cur_frm.doc.key, 'value'); | |||||
}, | |||||
() => done() | |||||
]); | |||||
}); |
@@ -0,0 +1,47 @@ | |||||
$(document).ready(function() { | |||||
var button = document.querySelector('#submit-button'); | |||||
var form = document.querySelector('#payment-form'); | |||||
var data = {{ frappe.form_dict | json }}; | |||||
var doctype = "{{ reference_doctype }}" | |||||
var docname = "{{ reference_docname }}" | |||||
braintree.dropin.create({ | |||||
authorization: "{{ client_token }}", | |||||
container: '#bt-dropin', | |||||
paypal: { | |||||
flow: 'vault' | |||||
} | |||||
}, function(createErr, instance) { | |||||
form.addEventListener('submit', function(event) { | |||||
event.preventDefault(); | |||||
instance.requestPaymentMethod(function(err, payload) { | |||||
if (err) { | |||||
console.log('Error', err); | |||||
return; | |||||
} | |||||
frappe.call({ | |||||
method: "frappe.templates.pages.integrations.braintree_checkout.make_payment", | |||||
freeze: true, | |||||
headers: { | |||||
"X-Requested-With": "XMLHttpRequest" | |||||
}, | |||||
args: { | |||||
"payload_nonce": payload.nonce, | |||||
"data": JSON.stringify(data), | |||||
"reference_doctype": doctype, | |||||
"reference_docname": docname | |||||
}, | |||||
callback: function(r) { | |||||
if (r.message && r.message.status == "Completed") { | |||||
window.location.href = r.message.redirect_to | |||||
} else if (r.message && r.message.status == "Error") { | |||||
window.location.href = r.message.redirect_to | |||||
} | |||||
} | |||||
}) | |||||
}); | |||||
}); | |||||
}); | |||||
}) |
@@ -0,0 +1,54 @@ | |||||
{% extends "templates/web.html" %} | |||||
{% block title %} Payment {% endblock %} | |||||
{%- block header -%}{% endblock %} | |||||
{% block script %} | |||||
<script src="https://js.braintreegateway.com/web/dropin/1.9.3/js/dropin.min.js"></script> | |||||
<script>{% include "templates/includes/integrations/braintree_checkout.js" %}</script> | |||||
{% endblock %} | |||||
{%- block page_content -%} | |||||
<div class="wrapper"> | |||||
<div class="checkout container"> | |||||
<header> | |||||
<div> | |||||
<img class="center" src="{{ header_img }}"></img> | |||||
</div> | |||||
</header> | |||||
<form id="payment-form"> | |||||
<section> | |||||
<div class="bt-drop-in-wrapper"> | |||||
<div id="bt-dropin"></div> | |||||
</div> | |||||
</section> | |||||
<button class="btn btn-primary" type="submit" id="submit-button"><span>{{ _("Pay") }} {{ amount }} {{ currency }}</span></button> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<style> | |||||
.checkout { | |||||
max-width: 60%; | |||||
} | |||||
.center { | |||||
margin:auto; | |||||
display: block; | |||||
} | |||||
#payment-form { | |||||
margin-top: 40px; | |||||
} | |||||
#submit-button { | |||||
float: right; | |||||
} | |||||
</style> | |||||
{% endblock %} |
@@ -0,0 +1,48 @@ | |||||
# Copyright (c) 2018, 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 | |||||
import json | |||||
from frappe.integrations.doctype.braintree_settings.braintree_settings import get_client_token, get_gateway_controller | |||||
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 | |||||
# 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.client_token = get_client_token(context.reference_docname) | |||||
context['amount'] = flt(context['amount']) | |||||
gateway_controller = get_gateway_controller(context.reference_docname) | |||||
context['header_img'] = frappe.db.get_value("Braintree Settings", gateway_controller, "header_img") | |||||
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 | |||||
@frappe.whitelist(allow_guest=True) | |||||
def make_payment(payload_nonce, data, reference_doctype, reference_docname): | |||||
data = json.loads(data) | |||||
data.update({ | |||||
"payload_nonce": payload_nonce | |||||
}) | |||||
gateway_controller = get_gateway_controller(reference_docname) | |||||
data = frappe.get_doc("Braintree Settings", gateway_controller).create_payment_request(data) | |||||
frappe.db.commit() | |||||
return data |