diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py deleted file mode 100644 index 65be5993ffc..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py +++ /dev/null @@ -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") diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js deleted file mode 100644 index 241129719b8..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js +++ /dev/null @@ -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(); - } -}); diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json deleted file mode 100644 index cca36536ac4..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json +++ /dev/null @@ -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 -} diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py deleted file mode 100644 index 4a29a6a21de..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py +++ /dev/null @@ -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 diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py deleted file mode 100644 index 379afe51ddc..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies and Contributors -# See license.txt - -import unittest - - -class TestGoCardlessSettings(unittest.TestCase): - pass diff --git a/pyproject.toml b/pyproject.toml index 7841c920546..604aa445858 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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",