* 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, | |||
"fields": [ | |||
{ | |||
"allow_bulk_edit": 0, | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
@@ -24,7 +25,7 @@ | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_global_search": 0, | |||
"in_list_view": 0, | |||
"in_list_view": 1, | |||
"in_standard_filter": 0, | |||
"label": "Gateway", | |||
"length": 0, | |||
@@ -40,6 +41,68 @@ | |||
"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_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, | |||
@@ -52,7 +115,7 @@ | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2017-03-09 12:40:56.176464", | |||
"modified": "2018-02-05 14:24:33.526645", | |||
"modified_by": "Administrator", | |||
"module": "Core", | |||
"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 |