refactor!: remove GoCardless Settings
This commit is contained in:
parent
f0859ecc60
commit
eded7871f3
@ -1,89 +0,0 @@
|
||||
# Copyright (c) 2018, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def webhooks():
|
||||
r = frappe.request
|
||||
if not r:
|
||||
return
|
||||
|
||||
if not authenticate_signature(r):
|
||||
raise frappe.AuthenticationError
|
||||
|
||||
gocardless_events = json.loads(r.get_data()) or []
|
||||
for event in gocardless_events["events"]:
|
||||
set_status(event)
|
||||
|
||||
return 200
|
||||
|
||||
|
||||
def set_status(event):
|
||||
resource_type = event.get("resource_type", {})
|
||||
|
||||
if resource_type == "mandates":
|
||||
set_mandate_status(event)
|
||||
|
||||
|
||||
def set_mandate_status(event):
|
||||
mandates = []
|
||||
if isinstance(event["links"], (list,)):
|
||||
for link in event["links"]:
|
||||
mandates.append(link["mandate"])
|
||||
else:
|
||||
mandates.append(event["links"]["mandate"])
|
||||
|
||||
if (
|
||||
event["action"] == "pending_customer_approval"
|
||||
or event["action"] == "pending_submission"
|
||||
or event["action"] == "submitted"
|
||||
or event["action"] == "active"
|
||||
):
|
||||
disabled = 0
|
||||
else:
|
||||
disabled = 1
|
||||
|
||||
for mandate in mandates:
|
||||
frappe.db.set_value("GoCardless Mandate", mandate, "disabled", disabled)
|
||||
|
||||
|
||||
def authenticate_signature(r):
|
||||
"""Returns True if the received signature matches the generated signature"""
|
||||
received_signature = frappe.get_request_header("Webhook-Signature")
|
||||
|
||||
if not received_signature:
|
||||
return False
|
||||
|
||||
for key in get_webhook_keys():
|
||||
computed_signature = hmac.new(key.encode("utf-8"), r.get_data(), hashlib.sha256).hexdigest()
|
||||
if hmac.compare_digest(str(received_signature), computed_signature):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_webhook_keys():
|
||||
def _get_webhook_keys():
|
||||
webhook_keys = [
|
||||
d.webhooks_secret
|
||||
for d in frappe.get_all(
|
||||
"GoCardless Settings",
|
||||
fields=["webhooks_secret"],
|
||||
)
|
||||
if d.webhooks_secret
|
||||
]
|
||||
|
||||
return webhook_keys
|
||||
|
||||
return frappe.cache().get_value("gocardless_webhooks_secret", _get_webhook_keys)
|
||||
|
||||
|
||||
def clear_cache():
|
||||
frappe.cache().delete_value("gocardless_webhooks_secret")
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2018, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('GoCardless Settings', {
|
||||
refresh: function(frm) {
|
||||
erpnext.utils.check_payments_app();
|
||||
}
|
||||
});
|
@ -1,211 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "field:gateway_name",
|
||||
"beta": 0,
|
||||
"creation": "2018-02-06 16:11:10.028249",
|
||||
"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": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Gateway Name",
|
||||
"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": "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": "access_token",
|
||||
"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": "Access Token",
|
||||
"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": "webhooks_secret",
|
||||
"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": "Webhooks Secret",
|
||||
"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": "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
|
||||
}
|
||||
],
|
||||
"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": "2022-02-12 14:18:47.209114",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"name": "GoCardless 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": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
# Copyright (c) 2018, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import frappe
|
||||
import gocardless_pro
|
||||
from frappe import _
|
||||
from frappe.integrations.utils import create_request_log
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import call_hook_method, cint, flt, get_url
|
||||
|
||||
from erpnext.utilities import payment_app_import_guard
|
||||
|
||||
|
||||
class GoCardlessSettings(Document):
|
||||
supported_currencies = ["EUR", "DKK", "GBP", "SEK", "AUD", "NZD", "CAD", "USD"]
|
||||
|
||||
def validate(self):
|
||||
self.initialize_client()
|
||||
|
||||
def initialize_client(self):
|
||||
self.environment = self.get_environment()
|
||||
try:
|
||||
self.client = gocardless_pro.Client(
|
||||
access_token=self.access_token, environment=self.environment
|
||||
)
|
||||
return self.client
|
||||
except Exception as e:
|
||||
frappe.throw(e)
|
||||
|
||||
def on_update(self):
|
||||
with payment_app_import_guard():
|
||||
from payments.utils import create_payment_gateway
|
||||
|
||||
create_payment_gateway(
|
||||
"GoCardless-" + self.gateway_name, settings="GoCardLess Settings", controller=self.gateway_name
|
||||
)
|
||||
call_hook_method("payment_gateway_enabled", gateway="GoCardless-" + self.gateway_name)
|
||||
|
||||
def on_payment_request_submission(self, data):
|
||||
if data.reference_doctype != "Fees":
|
||||
customer_data = frappe.db.get_value(
|
||||
data.reference_doctype, data.reference_name, ["company", "customer_name"], as_dict=1
|
||||
)
|
||||
|
||||
data = {
|
||||
"amount": flt(data.grand_total, data.precision("grand_total")),
|
||||
"title": customer_data.company.encode("utf-8"),
|
||||
"description": data.subject.encode("utf-8"),
|
||||
"reference_doctype": data.doctype,
|
||||
"reference_docname": data.name,
|
||||
"payer_email": data.email_to or frappe.session.user,
|
||||
"payer_name": customer_data.customer_name,
|
||||
"order_id": data.name,
|
||||
"currency": data.currency,
|
||||
}
|
||||
|
||||
valid_mandate = self.check_mandate_validity(data)
|
||||
if valid_mandate is not None:
|
||||
data.update(valid_mandate)
|
||||
|
||||
self.create_payment_request(data)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def check_mandate_validity(self, data):
|
||||
|
||||
if frappe.db.exists("GoCardless Mandate", dict(customer=data.get("payer_name"), disabled=0)):
|
||||
registered_mandate = frappe.db.get_value(
|
||||
"GoCardless Mandate", dict(customer=data.get("payer_name"), disabled=0), "mandate"
|
||||
)
|
||||
self.initialize_client()
|
||||
mandate = self.client.mandates.get(registered_mandate)
|
||||
|
||||
if (
|
||||
mandate.status == "pending_customer_approval"
|
||||
or mandate.status == "pending_submission"
|
||||
or mandate.status == "submitted"
|
||||
or mandate.status == "active"
|
||||
):
|
||||
return {"mandate": registered_mandate}
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_environment(self):
|
||||
if self.use_sandbox:
|
||||
return "sandbox"
|
||||
else:
|
||||
return "live"
|
||||
|
||||
def validate_transaction_currency(self, currency):
|
||||
if currency not in self.supported_currencies:
|
||||
frappe.throw(
|
||||
_(
|
||||
"Please select another payment method. Go Cardless does not support transactions in currency '{0}'"
|
||||
).format(currency)
|
||||
)
|
||||
|
||||
def get_payment_url(self, **kwargs):
|
||||
return get_url("./integrations/gocardless_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", "GoCardless")
|
||||
return self.create_charge_on_gocardless()
|
||||
|
||||
except Exception:
|
||||
frappe.log_error("Gocardless payment reqeust failed")
|
||||
return {
|
||||
"redirect_to": frappe.redirect_to_message(
|
||||
_("Server Error"),
|
||||
_(
|
||||
"There seems to be an issue with the server's GoCardless configuration. Don't worry, in case of failure, the amount will get refunded to your account."
|
||||
),
|
||||
),
|
||||
"status": 401,
|
||||
}
|
||||
|
||||
def create_charge_on_gocardless(self):
|
||||
redirect_to = self.data.get("redirect_to") or None
|
||||
redirect_message = self.data.get("redirect_message") or None
|
||||
|
||||
reference_doc = frappe.get_doc(
|
||||
self.data.get("reference_doctype"), self.data.get("reference_docname")
|
||||
)
|
||||
self.initialize_client()
|
||||
|
||||
try:
|
||||
payment = self.client.payments.create(
|
||||
params={
|
||||
"amount": cint(reference_doc.grand_total * 100),
|
||||
"currency": reference_doc.currency,
|
||||
"links": {"mandate": self.data.get("mandate")},
|
||||
"metadata": {
|
||||
"reference_doctype": reference_doc.doctype,
|
||||
"reference_document": reference_doc.name,
|
||||
},
|
||||
},
|
||||
headers={
|
||||
"Idempotency-Key": self.data.get("reference_docname"),
|
||||
},
|
||||
)
|
||||
|
||||
if (
|
||||
payment.status == "pending_submission"
|
||||
or payment.status == "pending_customer_approval"
|
||||
or payment.status == "submitted"
|
||||
):
|
||||
self.integration_request.db_set("status", "Authorized", update_modified=False)
|
||||
self.flags.status_changed_to = "Completed"
|
||||
self.integration_request.db_set("output", payment.status, update_modified=False)
|
||||
|
||||
elif payment.status == "confirmed" or payment.status == "paid_out":
|
||||
self.integration_request.db_set("status", "Completed", update_modified=False)
|
||||
self.flags.status_changed_to = "Completed"
|
||||
self.integration_request.db_set("output", payment.status, update_modified=False)
|
||||
|
||||
elif (
|
||||
payment.status == "cancelled"
|
||||
or payment.status == "customer_approval_denied"
|
||||
or payment.status == "charged_back"
|
||||
):
|
||||
self.integration_request.db_set("status", "Cancelled", update_modified=False)
|
||||
frappe.log_error("Gocardless payment cancelled")
|
||||
self.integration_request.db_set("error", payment.status, update_modified=False)
|
||||
else:
|
||||
self.integration_request.db_set("status", "Failed", update_modified=False)
|
||||
frappe.log_error("Gocardless payment failed")
|
||||
self.integration_request.db_set("error", payment.status, update_modified=False)
|
||||
|
||||
except Exception as e:
|
||||
frappe.log_error("GoCardless Payment Error")
|
||||
|
||||
if self.flags.status_changed_to == "Completed":
|
||||
status = "Completed"
|
||||
if "reference_doctype" in self.data and "reference_docname" in self.data:
|
||||
custom_redirect_to = None
|
||||
try:
|
||||
custom_redirect_to = frappe.get_doc(
|
||||
self.data.get("reference_doctype"), self.data.get("reference_docname")
|
||||
).run_method("on_payment_authorized", self.flags.status_changed_to)
|
||||
except Exception:
|
||||
frappe.log_error("Gocardless redirect failed")
|
||||
|
||||
if custom_redirect_to:
|
||||
redirect_to = custom_redirect_to
|
||||
|
||||
redirect_url = redirect_to
|
||||
else:
|
||||
status = "Error"
|
||||
redirect_url = "payment-failed"
|
||||
|
||||
if redirect_message:
|
||||
redirect_url += "&" + urlencode({"redirect_message": redirect_message})
|
||||
|
||||
redirect_url = get_url(redirect_url)
|
||||
|
||||
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 gocardless_initialization(doc):
|
||||
gateway_controller = get_gateway_controller(doc)
|
||||
settings = frappe.get_doc("GoCardless Settings", gateway_controller)
|
||||
client = settings.initialize_client()
|
||||
return client
|
@ -1,8 +0,0 @@
|
||||
# Copyright (c) 2018, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestGoCardlessSettings(unittest.TestCase):
|
||||
pass
|
@ -16,11 +16,9 @@ dependencies = [
|
||||
"holidays~=0.28",
|
||||
|
||||
# integration dependencies
|
||||
"gocardless-pro~=1.22.0",
|
||||
"googlemaps",
|
||||
"plaid-python~=7.2.1",
|
||||
"python-youtube~=0.8.0",
|
||||
"tweepy~=4.14.0",
|
||||
|
||||
# Not used directly - required by PyQRCode for PNG generation
|
||||
"pypng~=0.20220715.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user