From b16b081b399e2d3f086970d6698fd11ad8c4c6e0 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 21 Sep 2023 07:32:08 +0530 Subject: [PATCH 01/12] refactor!: remove `GoCardless Settings` --- .../doctype/gocardless_settings/gocardless_settings.js | 8 -------- pyproject.toml | 5 +---- 2 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js 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/pyproject.toml b/pyproject.toml index 6790664aab5..507fb0079ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,12 +15,9 @@ dependencies = [ "holidays~=0.28", # integration dependencies - "gocardless-pro~=1.37.0", - "ofxtools==0.8.16", + "googlemaps", "plaid-python~=7.2.1", "python-youtube~=0.8.0", - "sepaxml~=2.5.0", - "tweepy~=4.14.0", # Not used directly - required by PyQRCode for PNG generation "pypng~=0.20220715.0", -- GitLab From 8ff311780d91943974bfb3fdff4aa4485b0d5470 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 21 Sep 2023 07:32:39 +0530 Subject: [PATCH 02/12] refactor!: remove `Mpesa Settings` --- erpnext/erpnext_integrations/utils.py | 36 ++++++--------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py index 5a03d3c8d62..8984f1bee77 100644 --- a/erpnext/erpnext_integrations/utils.py +++ b/erpnext/erpnext_integrations/utils.py @@ -6,8 +6,6 @@ from urllib.parse import urlparse import frappe from frappe import _ -from erpnext import get_default_company - def validate_webhooks_request(doctype, hmac_key, secret_key="secret"): def innerfn(fn): @@ -47,30 +45,10 @@ def get_webhook_address(connector_name, method, exclude_uri=False, force_https=F return server_url -def create_mode_of_payment(gateway, payment_type="General"): - payment_gateway_account = frappe.db.get_value( - "Payment Gateway Account", {"payment_gateway": gateway}, ["payment_account"] - ) - - mode_of_payment = frappe.db.exists("Mode of Payment", gateway) - if not mode_of_payment and payment_gateway_account: - mode_of_payment = frappe.get_doc( - { - "doctype": "Mode of Payment", - "mode_of_payment": gateway, - "enabled": 1, - "type": payment_type, - "accounts": [ - { - "doctype": "Mode of Payment Account", - "company": get_default_company(), - "default_account": payment_gateway_account, - } - ], - } - ) - mode_of_payment.insert(ignore_permissions=True) - - return mode_of_payment - elif mode_of_payment: - return frappe.get_doc("Mode of Payment", mode_of_payment) +def get_tracking_url(carrier, tracking_number): + # Return the formatted Tracking URL. + tracking_url = "" + url_reference = frappe.get_value("Parcel Service", carrier, "url_reference") + if url_reference: + tracking_url = frappe.render_template(url_reference, {"tracking_number": tracking_number}) + return tracking_url -- GitLab From d73fd138854650511608a938ab030144686647c9 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Fri, 22 Sep 2023 18:52:26 +0530 Subject: [PATCH 03/12] refactor!: remove `GoCardless Templates` --- erpnext/templates/pages/integrations/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 erpnext/templates/pages/integrations/__init__.py diff --git a/erpnext/templates/pages/integrations/__init__.py b/erpnext/templates/pages/integrations/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 -- GitLab From 4dfe1f7582668338cb2e21f01c56c96f926793dd Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Mon, 25 Sep 2023 11:08:24 +0530 Subject: [PATCH 04/12] refactor!: remove `stripe_integration.py` --- .../doctype/payment_request/payment_request.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 8cc2af71775..9a8dac61aa8 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -20,10 +20,6 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import ( ) from erpnext.accounts.party import get_party_account from erpnext.accounts.utils import get_account_currency -from erpnext.e_commerce.shopping_cart.cart import get_shopping_cart_settings -from erpnext.erpnext_integrations.doctype.integration_references.integration_references import ( - can_make_immediate_payment, -) from erpnext.utilities import payment_app_import_guard @@ -480,9 +476,12 @@ class PaymentRequest(Document): return self.get_redirection() - def set_payment_method_registered(self): - """Called when payment method is registered for off-session payments""" - self.process_payment_immediately() + def create_subscription(self, payment_provider, gateway_controller, data): + if payment_provider == "stripe": + with payment_app_import_guard(): + from payments.payment_gateways.stripe_integration import create_stripe_subscription + + return create_stripe_subscription(gateway_controller, data) def get_redirection(self): redirect_to = "no-redirection" -- GitLab From 43c9af3ded673e38bc7720e7d2879b2e035e4ea9 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Tue, 26 Sep 2023 15:10:20 +0530 Subject: [PATCH 05/12] refactor: remove test `test_default_bank_account` --- .../plaid_settings/test_plaid_settings.py | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py index b2e2df5812e..4ad0fcce591 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py @@ -43,40 +43,6 @@ class TestPlaidSettings(unittest.TestCase): add_account_subtype("loan") self.assertEqual(frappe.get_doc("Bank Account Subtype", "loan").name, "loan") - def test_default_bank_account(self): - if not frappe.db.exists("Bank", "Citi"): - frappe.get_doc({"doctype": "Bank", "bank_name": "Citi"}).insert() - - bank_accounts = { - "account": { - "subtype": "checking", - "mask": "0000", - "type": "depository", - "id": "6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK", - "name": "Plaid Checking", - }, - "account_id": "6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK", - "link_session_id": "db673d75-61aa-442a-864f-9b3f174f3725", - "accounts": [ - { - "type": "depository", - "subtype": "checking", - "mask": "0000", - "id": "6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK", - "name": "Plaid Checking", - } - ], - "institution": {"institution_id": "ins_6", "name": "Citi"}, - } - - bank = json.dumps(frappe.get_doc("Bank", "Citi").as_dict(), default=json_handler) - company = frappe.db.get_single_value("Global Defaults", "default_company") - frappe.db.set_value("Company", company, "default_bank_account", None) - - self.assertRaises( - frappe.ValidationError, add_bank_accounts, response=bank_accounts, bank=bank, company=company - ) - def test_new_transaction(self): if not frappe.db.exists("Bank", "Citi"): frappe.get_doc({"doctype": "Bank", "bank_name": "Citi"}).insert() -- GitLab From c16b453c6bde5177e81a43c0e8e5c014418c79b9 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Wed, 27 Sep 2023 15:27:29 +0530 Subject: [PATCH 06/12] chore: patch to delete Payment Gateways --- erpnext/patches.txt | 23 +++---------------- .../v15_0/delete_payment_gateway_doctypes.py | 6 +++++ 2 files changed, 9 insertions(+), 20 deletions(-) create mode 100644 erpnext/patches/v15_0/delete_payment_gateway_doctypes.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 5d576c8810a..0ef5f9a15a7 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -351,25 +351,8 @@ execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for erpnext.patches.v15_0.correct_asset_value_if_je_with_workflow erpnext.patches.v15_0.delete_woocommerce_settings_doctype erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults - -# @dokos -erpnext.patches.dokos.v3_0.add_expiration_date_to_booking_legder -erpnext.patches.dokos.v3_0.setup_item_wise_tax_info_for_france #2023-05-02 -execute:frappe.delete_doc('Report', 'GoCardless Payments', ignore_missing=True) -erpnext.patches.dokos.v3_0.update_custom_fields_for_france #2023-10-06 -erpnext.accounts.doctype.subscription.patches.set_an_invoicing_day_on_existing_subscriptions -erpnext.patches.dokos.v3_0.retry_gocardless_payout_webhooks -erpnext.patches.dokos.v3_0.gocardless_payments_corrections -erpnext.patches.dokos.v3_0.migrate_to_new_booking_credit_system -erpnext.patches.dokos.v3_0.fix_french_success_action_message_for_quotation_and_others -erpnext.patches.dokos.v3_0.set_venue_settings_defaults -erpnext.patches.dokos.v3_0.set_units_of_measure_in_venue_settings -erpnext.accounts.doctype.mode_of_payment.patches.update_mode_of_payment_data_from_payment_gateway -execute:frappe.delete_doc_if_exists("DocType", "Subscription Gateway Plans") -execute:frappe.delete_doc_if_exists("DocType", "Subscription Template") -execute:frappe.delete_doc_if_exists("DocType", "Portal Payment Gateways Template") -execute:frappe.delete_doc_if_exists("DocType", "Portal Payment Gateways") -execute:frappe.delete_doc_if_exists("DocType", "Subscription Event") - +erpnext.patches.v14_0.update_invoicing_period_in_subscription +execute:frappe.delete_doc("Page", "welcome-to-erpnext") +erpnext.patches.v15_0.delete_payment_gateway_doctypes # below migration patch should always run last erpnext.patches.v14_0.migrate_gl_to_payment_ledger diff --git a/erpnext/patches/v15_0/delete_payment_gateway_doctypes.py b/erpnext/patches/v15_0/delete_payment_gateway_doctypes.py new file mode 100644 index 00000000000..959b0657803 --- /dev/null +++ b/erpnext/patches/v15_0/delete_payment_gateway_doctypes.py @@ -0,0 +1,6 @@ +import frappe + + +def execute(): + for dt in ("GoCardless Settings", "GoCardless Mandate", "Mpesa Settings"): + frappe.delete_doc("DocType", dt, ignore_missing=True) -- GitLab From 69e2b7272e12a1fe6f442ddea5434cc76bcec4af Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Tue, 17 Oct 2023 09:42:05 +0200 Subject: [PATCH 07/12] fix: Remove GoCardless Settings --- .../payment_request/payment_request.py | 13 +- .../doctype/gocardless_settings/__init__.py | 96 -------- .../gocardless_settings/api/__init__.py | 6 - .../gocardless_settings/api/customers.py | 46 ---- .../doctype/gocardless_settings/api/events.py | 13 -- .../gocardless_settings/api/mandates.py | 39 ---- .../gocardless_settings/api/payments.py | 35 --- .../gocardless_settings/api/payout_items.py | 7 - .../gocardless_settings/api/payouts.py | 10 - .../gocardless_settings.json | 78 ------- .../gocardless_settings.py | 212 ------------------ .../gocardless_settings_dashboard.py | 8 - .../test_gocardless_settings.py | 9 - .../webhook_events/__init__.py | 1 - .../webhook_events/gocardless.py | 156 ------------- erpnext/erpnext_integrations/utils.py | 9 - erpnext/patches.txt | 22 ++ pyproject.toml | 3 +- 18 files changed, 31 insertions(+), 732 deletions(-) delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/api/__init__.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/api/customers.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/api/events.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/api/mandates.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/api/payments.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/api/payout_items.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/api/payouts.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings_dashboard.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/__init__.py delete mode 100644 erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/gocardless.py diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 9a8dac61aa8..8cc2af71775 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -20,6 +20,10 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import ( ) from erpnext.accounts.party import get_party_account from erpnext.accounts.utils import get_account_currency +from erpnext.e_commerce.shopping_cart.cart import get_shopping_cart_settings +from erpnext.erpnext_integrations.doctype.integration_references.integration_references import ( + can_make_immediate_payment, +) from erpnext.utilities import payment_app_import_guard @@ -476,12 +480,9 @@ class PaymentRequest(Document): return self.get_redirection() - def create_subscription(self, payment_provider, gateway_controller, data): - if payment_provider == "stripe": - with payment_app_import_guard(): - from payments.payment_gateways.stripe_integration import create_stripe_subscription - - return create_stripe_subscription(gateway_controller, data) + def set_payment_method_registered(self): + """Called when payment method is registered for off-session payments""" + self.process_payment_immediately() def get_redirection(self): redirect_to = "no-redirection" 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 8445fcc49b6..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies and contributors -# For license information, please see license.txt - - -import json -from urllib.parse import parse_qs - -import frappe -from frappe import _ -from gocardless_pro import webhooks as gocardless_webhooks -from gocardless_pro.errors import InvalidSignatureError - - -@frappe.whitelist(allow_guest=True) -def webhooks(): - r = frappe.request - if not r: - return - - account, events = get_events(r) - for event in events: - try: - doc = create_new_integration_log(event, account) - - frappe.enqueue( - method="erpnext.erpnext_integrations.doctype.gocardless_settings.gocardless_settings.handle_webhooks", - queue="long", - timeout=600, - is_async=True, - **{"doctype": "Integration Request", "docname": doc.name} - ) - except Exception: - frappe.log_error(_("GoCardless webhooks processing error")) - - frappe.response.message = "Webhook received and event type handled" - frappe.response.http_status_code = 200 - - -def get_events(request): - account, secret = get_api_key(request) - received_signature = frappe.get_request_header("Webhook-Signature") - payload = request.get_data() - try: - data = gocardless_webhooks.parse(payload, secret, received_signature) - return account, data - - except InvalidSignatureError: - frappe.log_error(_("GoCardless webhook error")) - except Exception: - frappe.log_error(_("GoCardless webhook error")) - - -def get_api_key(request): - account = None - if request.query_string: - parsed_qs = parse_qs(frappe.safe_decode(request.query_string)) - account = parsed_qs.get("account") - - if isinstance(account, list): - account = account[0] - - if account: - return account, frappe.db.get_value("GoCardless Settings", account, "webhooks_secret") - else: - gocardless_accounts = frappe.get_all("GoCardless Settings") - if len(gocardless_accounts) > 1: - frappe.log_error( - message=_("Please define your GoCardless account in the webhook URL's query string"), - title=_("GoCardless webhook error"), - ) - else: - return gocardless_accounts[0].get("name"), frappe.db.get_value( - "GoCardless Settings", gocardless_accounts[0].get("name"), "webhooks_secret" - ) - - -def create_new_integration_log(event, account): - integration_request = frappe.get_doc( - { - "doctype": "Integration Request", - "request_description": "Webhook", - "integration_request_service": "GoCardless", - "service_document": event.attributes.get("resource_type"), - "service_status": event.attributes.get("action"), - "service_id": event.attributes.get("id"), - "data": json.dumps(event.attributes, indent=4), - "payment_gateway_controller": account, - } - ) - - integration_request.flags._name = event.attributes.get("id") - - integration_request.insert(ignore_permissions=True) - frappe.db.commit() - - return integration_request diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/__init__.py deleted file mode 100644 index 1d6a8588dc7..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .customers import GoCardlessCustomers -from .events import GoCardlessEvents -from .mandates import GoCardlessMandates -from .payments import GoCardlessPayments -from .payout_items import GoCardlessPayoutItems -from .payouts import GoCardlessPayouts diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/customers.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/customers.py deleted file mode 100644 index c84596c8935..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/customers.py +++ /dev/null @@ -1,46 +0,0 @@ -import frappe - - -class GoCardlessCustomers: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - # Restricted to GoCardless Pro - def create(self, **kwargs): - return self.client.customers.create(params=kwargs) - - def get(self, id): - return self.client.customers.get(id) - - def update(self, id, **kwargs): - return self.client.customers.update(id, params=kwargs) - - def remove(self, id): - return self.client.customers.remove( - id, - ) - - def get_list(self, **kwargs): - return self.client.customers.list(params=kwargs) - - def register(self, gocardless_id, customer): - try: - if frappe.db.exists("Integration References", dict(customer=customer)): - doc = frappe.get_doc("Integration References", dict(customer=customer)) - doc.gocardless_customer_id = gocardless_id - doc.gocardless_settings = self.gateway.name - doc.save(ignore_permissions=True) - - else: - frappe.get_doc( - { - "doctype": "Integration References", - "customer": customer, - "gocardless_customer_id": gocardless_id, - "gocardless_settings": self.gateway.name, - } - ).insert(ignore_permissions=True) - frappe.db.commit() - except Exception as e: - frappe.log_error(e, "GoCardless Customer ID Registration Error") diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/events.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/events.py deleted file mode 100644 index 871bdcb8553..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/events.py +++ /dev/null @@ -1,13 +0,0 @@ -import frappe - - -class GoCardlessEvents: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - def get(self, id): - return self.client.events.get(id) - - def get_list(self, **kwargs): - return self.client.events.list(params=kwargs) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/mandates.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/mandates.py deleted file mode 100644 index c32303cded2..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/mandates.py +++ /dev/null @@ -1,39 +0,0 @@ -import frappe -from frappe.utils import nowdate - - -class GoCardlessMandates: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - # Restricted to GoCardless Pro - def create(self, **kwargs): - return self.client.mandates.create(params=kwargs) - - def get(self, id): - return self.client.mandates.get(id) - - def update(self, id, **kwargs): - return self.client.mandates.update(id, params=kwargs) - - def remove(self, id): - return self.client.mandates.remove( - id, - ) - - def get_list(self, **kwargs): - return self.client.mandates.list(params=kwargs) - - def register(self, id, customer): - if not frappe.db.exists("Sepa Mandate", id): - frappe.get_doc( - { - "doctype": "Sepa Mandate", - "mandate": id, - "customer": customer, - "registered_on_gocardless": 1, - "creation_date": nowdate(), - } - ).insert(ignore_permissions=True) - frappe.db.commit() diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payments.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payments.py deleted file mode 100644 index 4c729b25a49..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payments.py +++ /dev/null @@ -1,35 +0,0 @@ -from payments.payment_gateways.doctype.stripe_settings.idempotency import ( - IdempotencyKey, - handle_idempotency, -) - - -class GoCardlessPayments: - def __init__(self, gateway, reference=None): - self.gateway = gateway - self.client = self.gateway.client - self.reference = reference - - @handle_idempotency - def create(self, **kwargs): - return self.client.payments.create( - params=kwargs, - headers={ - "Idempotency-Key": IdempotencyKey("payments", "create", self.reference).get(), - }, - ) - - def get(self, id): - return self.client.payments.get(id) - - def get_list(self, params): - return self.client.payments.list(params=params) - - def update(self, id, **kwargs): - return self.client.payments.update(id, params=kwargs) - - def cancel(self, id, **kwargs): - return self.client.payments.cancel(id, params=kwargs) - - def retry(self, id, **kwargs): - return self.client.payments.retry(id, params=kwargs) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payout_items.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payout_items.py deleted file mode 100644 index 843e1f20492..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payout_items.py +++ /dev/null @@ -1,7 +0,0 @@ -class GoCardlessPayoutItems: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - def get_list(self, payout, **kwargs): - return self.client.payout_items.list(params=dict({"payout": payout}, **kwargs)) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payouts.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payouts.py deleted file mode 100644 index 77b71b67366..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payouts.py +++ /dev/null @@ -1,10 +0,0 @@ -class GoCardlessPayouts: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - def get(self, id): - return self.client.payouts.get(id) - - def get_list(self, **kwargs): - return self.client.payouts.list(params=kwargs) 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 34d310ac085..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "actions": [], - "autoname": "field:gateway_name", - "creation": "2018-02-06 16:11:10.028249", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "gateway_name", - "access_token", - "webhooks_secret", - "use_sandbox", - "settings_section", - "bank_account" - ], - "fields": [ - { - "fieldname": "gateway_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Payment Gateway Name", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "access_token", - "fieldtype": "Password", - "in_list_view": 1, - "label": "Access Token", - "reqd": 1 - }, - { - "fieldname": "webhooks_secret", - "fieldtype": "Data", - "label": "Webhooks Secret" - }, - { - "default": "0", - "fieldname": "use_sandbox", - "fieldtype": "Check", - "label": "Use Sandbox" - }, - { - "fieldname": "settings_section", - "fieldtype": "Section Break", - "label": "Settings" - }, - { - "fieldname": "bank_account", - "fieldtype": "Link", - "label": "Bank Account", - "options": "Bank Account" - } - ], - "links": [], - "modified": "2022-02-12 14:18:47.209114", - "modified_by": "Administrator", - "module": "ERPNext Integrations", - "name": "GoCardless Settings", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file 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 629aece27f2..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py +++ /dev/null @@ -1,212 +0,0 @@ -# Copyright (c) 2023, Dokos SAS and contributors -# For license information, please see license.txt - - -from urllib.parse import urlencode - -import frappe -import gocardless_pro -from frappe import _ -from frappe.utils import call_hook_method, cint, flt, get_url -from gocardless_pro import errors -from payments.utils.utils import PaymentGatewayController - -from erpnext.erpnext_integrations.doctype.gocardless_settings.api import ( - GoCardlessCustomers, - GoCardlessMandates, - GoCardlessPayments, - GoCardlessPayoutItems, - GoCardlessPayouts, -) -from erpnext.erpnext_integrations.doctype.gocardless_settings.webhook_events import ( - GoCardlessWebhookHandler, -) -from erpnext.utilities import payment_app_import_guard - - -class GoCardlessSettings(PaymentGatewayController): - supported_currencies = ["AUD", "CAD", "DKK", "EUR", "GBP", "NZD", "SEK", "USD"] - - def __init__(self, *args, **kwargs): - super(GoCardlessSettings, self).__init__(*args, **kwargs) - if not self.is_new(): - self.initialize_client() - - def validate(self): - self.initialize_client() - - def initialize_client(self): - self.environment = self.get_environment() - try: - self.client = gocardless_pro.Client( - access_token=self.get_password(fieldname="access_token", raise_exception=False), - environment=self.environment, - ) - return self.client - except Exception as e: - frappe.throw(str(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 immediate_payment_processing( - self, reference, customer, amount, currency, description, metadata - ): - try: - processed_data = dict( - amount=round(flt(amount) * 100.0), - currency=currency, - description=description, - reference=reference, - links={}, - metadata=metadata, - ) - - valid_mandate = self.check_mandate_validity(customer) - if valid_mandate.get("mandate"): - processed_data["links"] = valid_mandate - - return getattr(GoCardlessPayments(self, reference).create(**processed_data), "id", None) - else: - frappe.throw(_("This customer has no valid mandate")) - - except Exception: - self.log_error( - _("GoCardless direct processing failed for {0}".format(reference)), - ) - - def check_mandate_validity(self, customer=None): - if customer and frappe.db.exists( - "Sepa Mandate", dict(customer=customer, status=["not in", ["Cancelled", "Expired", "Failed"]]) - ): - registered_mandate = frappe.db.get_value( - "Sepa Mandate", - dict(customer=customer, status=["not in", ["Cancelled", "Expired", "Failed"]]), - "mandate", - ) - - try: - mandate = GoCardlessMandates(self).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} - except errors.InvalidApiUsageError: - pass - return {} - - def get_environment(self): - return "sandbox" if self.use_sandbox else "live" - - def validate_transaction_currency(self, currency): - if currency not in self.supported_currencies: - frappe.throw( - _( - "Please select another payment method. GoCardless 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 handle_redirect_flow(self, redirect_flow, reference_document): - customer = reference_document.get("customer") or reference_document.get_customer() - if not customer: - return - - GoCardlessMandates(self).register(redirect_flow.links.mandate, customer) - - GoCardlessCustomers(self).register(redirect_flow.links.customer, customer) - - payment = GoCardlessPayments(self, reference_document.name).create( - amount=cint((reference_document.get("grand_total") or reference_document.get("amount")) * 100), - currency=reference_document.get("currency"), - description=reference_document.get("subject") or reference_document.get("description"), - reference=reference_document.name, - links={"mandate": redirect_flow.links.mandate}, - metadata={ - "reference_doctype": reference_document.doctype, - "reference_name": reference_document.name, - }, - ) - - return getattr(payment, "id") - - def get_transaction_fees(self, payments): - gc_payments = GoCardlessPayments(self).get(payments) - gc_payment_links = getattr(gc_payments, "links", {}) - gc_payout = getattr(gc_payment_links, "payout") - - if not gc_payout: - frappe.throw(_("This payment has not been paid out yet")) - - payout_items = GoCardlessPayoutItems(self).get_list(gc_payout) - - tax_amount = self.get_tax_amount(payout_items.records, gc_payments.id) - fees = frappe._dict( - base_amount=self.get_base_amount(payout_items.records, gc_payments.id), - fee_amount=self.get_fee_amount(payout_items.records, gc_payments.id) - tax_amount, - tax_amount=tax_amount, - exchange_rate=self.get_exchange_rate(GoCardlessPayouts(self).get(gc_payout)), - ) - - return fees - - @staticmethod - def get_base_amount(payout_items, payments): - paid_amount = sum( - [ - flt(record.amount) - for record in payout_items - if (record.type == "payment_paid_out" and record.links.payment == payments) - ] - ) - return paid_amount / 100 - - @staticmethod - def get_fee_amount(payout_items, payments): - fee_amount = sum( - [ - flt(record.amount) - for record in payout_items - if ( - (record.type == "gocardless_fee" or record.type == "app_fee") - and record.links.payment == payments - ) - ] - ) - return abs(fee_amount) / 100 - - @staticmethod - def get_tax_amount(payout_items, payments): - taxes = [] - for x in payout_items: - if (x.type == "gocardless_fee" or x.type == "app_fee") and x.links.payment == payments: - taxes.extend(x.taxes) - - return abs(sum([flt(x.get("amount")) for x in taxes])) / 100 - - @staticmethod - def get_exchange_rate(payout): - return flt(getattr(payout.fx, "exchange_rate", 1) or 1) - - -def handle_webhooks(**kwargs): - integration_request = frappe.get_doc(kwargs.get("doctype"), kwargs.get("docname")) - - if integration_request.service_document in ["mandates", "payments"]: - GoCardlessWebhookHandler(**kwargs) - else: - integration_request.handle_failure( - {"message": _("This type of event is not handled")}, "Not Handled" - ) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings_dashboard.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings_dashboard.py deleted file mode 100644 index 922a8b6fe11..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings_dashboard.py +++ /dev/null @@ -1,8 +0,0 @@ -from frappe import _ - - -def get_data(): - return { - "fieldname": "gateway_controller", - "transactions": [{"label": _("Payment Gateways"), "items": ["Payment Gateway"]}], - } 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 505d2848d5d..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies and Contributors -# See license.txt - - -import unittest - - -class TestGoCardlessSettings(unittest.TestCase): - pass diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/__init__.py deleted file mode 100644 index 0bb84056ace..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .gocardless import GoCardlessWebhookHandler \ No newline at end of file diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/gocardless.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/gocardless.py deleted file mode 100644 index de564e2d38a..00000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/gocardless.py +++ /dev/null @@ -1,156 +0,0 @@ -import json - -import frappe -from frappe import _ - -from erpnext.erpnext_integrations.doctype.gocardless_settings.api import ( - GoCardlessMandates, - GoCardlessPayments, -) - -MANDATES_STATUS = { - "customer_approval_granted": "Pending Customer Approval", - "customer_approval_skipped": "Pending Submission", - "active": "Active", - "cancelled": "Cancelled", - "failed": "Failed", - "transferred": "Submitted", - "expired": "Expired", - "submitted": "Submitted", - "resubmission_requested": "Pending Submission", - "reinstated": "Active", - "replaced": "Cancelled", - "created": "Pending Submission", -} - -PAYMENTS_STATUS = { - "created": "Pending", - "submitted": "Pending", - "confirmed": "Paid", - "cancelled": "Failed", - "failed": "Failed", - "paid_out": "Paid", -} - - -class GoCardlessWebhookHandler: - def __init__(self, **kwargs): - self.integration_request = frappe.get_doc(kwargs.get("doctype"), kwargs.get("docname")) - self.integration_request.db_set("error", None) - self.data = json.loads(self.integration_request.get("data")) - self.payment = self.data.get("links", {}).get("payment") - self.metadata = {} - self.gocardless_settings = frappe.get_doc( - "GoCardless Settings", self.integration_request.payment_gateway_controller - ) - - if self.integration_request.service_document == "payments": - self.get_reference_documents() - - self.integration_request.load_from_db() - self.handle_webhook() - - def get_reference_documents(self): - gc_payment = GoCardlessPayments(self.gocardless_settings).get(self.payment) - self.metadata = getattr(gc_payment, "metadata", {}) - - for k in ("reference_doctype", "reference_docname", "reference_name"): - if k in self.metadata: - key = "reference_docname" if k == "reference_name" else k - self.integration_request.db_set(key, self.metadata[k]) - - # For compatibility - if "payment_request" in self.metadata: - self.integration_request.db_set("reference_doctype", "Payment Request") - self.integration_request.db_set("reference_docname", self.metadata["payment_request"]) - - def handle_webhook(self): - action = self.data.get("action") - service = self.integration_request.service_document - - if service == "payments": - self.handle_payments(action) - - elif service == "mandates": - self.handle_mandates(action) - - def handle_payments(self, action): - if action not in PAYMENTS_STATUS: - return self.integration_request.handle_failure( - response={"message": _("This type of event is not handled")}, status="Not Handled" - ) - - elif not ( - self.integration_request.reference_doctype and self.integration_request.reference_docname - ): - return self.integration_request.handle_failure( - response={"message": _("This event contains not metadata")}, status="Failed" - ) - - elif not frappe.db.exists( - self.integration_request.reference_doctype, self.integration_request.reference_docname - ): - return self.integration_request.handle_failure( - response={"message": _("The reference document does not exist")}, status="Failed" - ) - - try: - reference_document = frappe.get_doc( - self.integration_request.reference_doctype, self.integration_request.reference_docname - ) - response = reference_document.run_method( - "on_payment_authorized", status=PAYMENTS_STATUS[action], reference_no=self.payment - ) - - self.integration_request.handle_success(response={"message": response}) - - except Exception: - self.integration_request.handle_failure( - response={"message": frappe.get_traceback()}, status="Failed" - ) - - def handle_mandates(self, action): - if action not in MANDATES_STATUS: - return self.integration_request.handle_failure( - response={"message": _("This type of event is not handled")}, status="Not Handled" - ) - - try: - response = self.change_mandate_status() - self.integration_request.handle_success(response={"message": response}) - - except Exception: - self.integration_request.handle_failure( - response={"message": frappe.get_traceback()}, status="Failed" - ) - - def change_mandate_status(self): - mandate = self.data.get("links", {}).get("mandate") - if not frappe.db.exists("Sepa Mandate", mandate): - self.create_mandate(mandate) - - sepa_mandate = self.set_mandate_status(mandate, MANDATES_STATUS.get(self.data.get("action"))) - - self.integration_request.db_set("reference_doctype", "Sepa Mandate") - self.integration_request.db_set("reference_docname", sepa_mandate) - - return _("Mandate updated successfully") - - def create_mandate(self, mandate): - gc_mandate = GoCardlessMandates(self.gocardless_settings).get(mandate) or {} - gocardless_customer = gc_mandate.links.customer - customer = frappe.db.get_value( - "Integration References", {"gocardless_customer_id": gocardless_customer}, ["customer"] - ) - - if customer: - GoCardlessMandates(self.gocardless_settings).register(mandate, customer) - - def set_mandate_status(self, mandate, status): - doc = frappe.get_doc("Sepa Mandate", mandate) - if doc.status != status: - doc.status = status - doc.flags.ignore_permissions = True - doc.save() - - return doc.name diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py index 8984f1bee77..f72b47250b6 100644 --- a/erpnext/erpnext_integrations/utils.py +++ b/erpnext/erpnext_integrations/utils.py @@ -43,12 +43,3 @@ def get_webhook_address(connector_name, method, exclude_uri=False, force_https=F server_url = f"{scheme}://{netloc}/api/method/{endpoint}" return server_url - - -def get_tracking_url(carrier, tracking_number): - # Return the formatted Tracking URL. - tracking_url = "" - url_reference = frappe.get_value("Parcel Service", carrier, "url_reference") - if url_reference: - tracking_url = frappe.render_template(url_reference, {"tracking_number": tracking_number}) - return tracking_url diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 0ef5f9a15a7..1c73a5c2946 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -354,5 +354,27 @@ erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults erpnext.patches.v14_0.update_invoicing_period_in_subscription execute:frappe.delete_doc("Page", "welcome-to-erpnext") erpnext.patches.v15_0.delete_payment_gateway_doctypes + +# @dokos +erpnext.patches.dokos.v3_0.add_expiration_date_to_booking_legder +erpnext.patches.dokos.v3_0.setup_item_wise_tax_info_for_france #2023-05-02 +execute:frappe.delete_doc('Report', 'GoCardless Payments', ignore_missing=True) +erpnext.patches.dokos.v3_0.update_custom_fields_for_france #2023-10-06 +erpnext.accounts.doctype.subscription.patches.set_an_invoicing_day_on_existing_subscriptions +erpnext.patches.dokos.v3_0.retry_gocardless_payout_webhooks +erpnext.patches.dokos.v3_0.gocardless_payments_corrections +erpnext.patches.dokos.v3_0.migrate_to_new_booking_credit_system +erpnext.patches.dokos.v3_0.fix_french_success_action_message_for_quotation_and_others +erpnext.patches.dokos.v3_0.set_venue_settings_defaults +erpnext.patches.dokos.v3_0.set_units_of_measure_in_venue_settings +erpnext.accounts.doctype.mode_of_payment.patches.update_mode_of_payment_data_from_payment_gateway +execute:frappe.delete_doc_if_exists("DocType", "Subscription Gateway Plans") +execute:frappe.delete_doc_if_exists("DocType", "Subscription Template") +execute:frappe.delete_doc_if_exists("DocType", "Portal Payment Gateways Template") +execute:frappe.delete_doc_if_exists("DocType", "Portal Payment Gateways") +execute:frappe.delete_doc_if_exists("DocType", "Subscription Event") +# @dokos + + # below migration patch should always run last erpnext.patches.v14_0.migrate_gl_to_payment_ledger diff --git a/pyproject.toml b/pyproject.toml index 507fb0079ad..cb2d48820d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,9 +15,10 @@ dependencies = [ "holidays~=0.28", # integration dependencies - "googlemaps", + "ofxtools==0.8.16", "plaid-python~=7.2.1", "python-youtube~=0.8.0", + "sepaxml~=2.5.0", # Not used directly - required by PyQRCode for PNG generation "pypng~=0.20220715.0", -- GitLab From d44bdcf8a3fa46eda39edfd3daccb88f257f6b52 Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Tue, 17 Oct 2023 10:06:51 +0200 Subject: [PATCH 08/12] fix: remove missing patch --- erpnext/patches.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 1c73a5c2946..20703e25b02 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -351,7 +351,6 @@ execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for erpnext.patches.v15_0.correct_asset_value_if_je_with_workflow erpnext.patches.v15_0.delete_woocommerce_settings_doctype erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults -erpnext.patches.v14_0.update_invoicing_period_in_subscription execute:frappe.delete_doc("Page", "welcome-to-erpnext") erpnext.patches.v15_0.delete_payment_gateway_doctypes -- GitLab From a6f02b70836d247987261daa2faf35f3f344fc95 Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Tue, 17 Oct 2023 10:55:57 +0200 Subject: [PATCH 09/12] fix: Mode of payment permissions --- .../mode_of_payment/mode_of_payment.json | 56 ++++++++++++++++++- .../mode_of_payment/mode_of_payment.py | 24 ++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json index dcab3149ca4..6ecbe0e50fd 100644 --- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json +++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json @@ -119,13 +119,65 @@ "icon": "fa fa-credit-card", "idx": 1, "links": [], - "modified": "2023-08-29 17:36:59.548452", + "modified": "2023-10-17 10:28:17.097987", "modified_by": "Administrator", "module": "Accounts", "name": "Mode of Payment", "naming_rule": "By fieldname", "owner": "Administrator", - "permissions": [], + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "select": 1, + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales Master Manager", + "select": 1, + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "select": 1, + "share": 1, + "write": 1 + }, + { + "create": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "select": 1, + "share": 1, + "write": 1 + } + ], "quick_entry": 1, "show_name_in_global_search": 1, "show_preview_popup": 1, diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py index d4d9060f120..25038ac6c6b 100644 --- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py +++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py @@ -8,6 +8,30 @@ from frappe.model.document import Document class ModeofPayment(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + from erpnext.accounts.doctype.mode_of_payment_account.mode_of_payment_account import ( + ModeofPaymentAccount, + ) + + accounts: DF.Table[ModeofPaymentAccount] + cost_center: DF.Link | None + enabled: DF.Check + fee_account: DF.Link | None + icon: DF.Literal["Credit Card", "Wire Transfer", "Bank Draft", "Cash", "Cheque", "Other"] + mode_of_payment: DF.Data + payment_gateway: DF.Link | None + portal_description: DF.MarkdownEditor | None + tax_account: DF.Link | None + type: DF.Literal["Cash", "Bank"] + # end: auto-generated types + def validate(self): self.validate_accounts() self.validate_repeating_companies() -- GitLab From 8b6fbd833b253bd28e41fb46e4e7cf34a3d907d8 Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Tue, 17 Oct 2023 15:52:12 +0200 Subject: [PATCH 10/12] fix: Remove duplicate patch --- erpnext/patches.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 20703e25b02..ceebe4a2642 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -351,7 +351,6 @@ execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for erpnext.patches.v15_0.correct_asset_value_if_je_with_workflow erpnext.patches.v15_0.delete_woocommerce_settings_doctype erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults -execute:frappe.delete_doc("Page", "welcome-to-erpnext") erpnext.patches.v15_0.delete_payment_gateway_doctypes # @dokos -- GitLab From 772099866ac203071cc8e88573807b765892c778 Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Tue, 17 Oct 2023 15:54:43 +0200 Subject: [PATCH 11/12] fix: Migrate checkout pages to payments --- .../integrations/gocardless_checkout.html | 14 -- .../pages/integrations/gocardless_checkout.py | 125 ------------------ .../integrations/gocardless_confirmation.html | 14 -- .../integrations/gocardless_confirmation.py | 45 ------- 4 files changed, 198 deletions(-) delete mode 100644 erpnext/templates/pages/integrations/gocardless_checkout.html delete mode 100644 erpnext/templates/pages/integrations/gocardless_checkout.py delete mode 100644 erpnext/templates/pages/integrations/gocardless_confirmation.html delete mode 100644 erpnext/templates/pages/integrations/gocardless_confirmation.py diff --git a/erpnext/templates/pages/integrations/gocardless_checkout.html b/erpnext/templates/pages/integrations/gocardless_checkout.html deleted file mode 100644 index 3b855a45a7b..00000000000 --- a/erpnext/templates/pages/integrations/gocardless_checkout.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %} Payment {% endblock %} - -{%- block header -%}{% endblock %} - -{%- block page_content -%} -
-

- {{ _("Loading Payment System") }} -

-
- -{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/pages/integrations/gocardless_checkout.py b/erpnext/templates/pages/integrations/gocardless_checkout.py deleted file mode 100644 index d36991b8756..00000000000 --- a/erpnext/templates/pages/integrations/gocardless_checkout.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (c) 2020, Dokos SAS and Contributors -# License: See license.txt - -import frappe -from frappe import _ -from frappe.contacts.doctype.contact.contact import get_default_contact -from payments.utils.utils import get_gateway_controller -from frappe.utils import fmt_money, get_url, check_format - -expected_keys = ( - "amount", - "title", - "description", - "reference_doctype", - "reference_docname", - "payer_name", - "payer_email", - "order_id", - "currency", -) - - -def get_context(context): - context.no_cache = 1 - - if not (set(expected_keys) - set(list(frappe.form_dict))): - for key in expected_keys: - context[key] = frappe.form_dict[key] - - gateway_controller = get_gateway_controller( - context.reference_doctype, context.reference_docname - ) - if not gateway_controller: - redirect_to_invalid_link() - - reference_document = frappe.get_doc(context.reference_doctype, context.reference_docname) - else: - print(set(expected_keys) - set(list(frappe.form_dict))) - redirect_to_invalid_link() - - success_url = get_url( - f"./integrations/gocardless_confirmation?reference_doctype={context.reference_doctype}&reference_docname={context.reference_docname}" - ) - - try: - gocardless_settings = frappe.get_cached_doc("GoCardless Settings", gateway_controller) - redirect_flow = gocardless_settings.client.redirect_flows.create( - params={ - "description": _("Pay {0}").format( - fmt_money(amount=context.amount, currency=context.currency) - ), - "session_token": f"{context.reference_doctype}&{context.reference_docname}", - "success_redirect_url": success_url, - "prefilled_customer": PrefilledCustomer(reference_document, context).get(), - "metadata": { - "reference_doctype": context.reference_doctype, - "reference_name": context.reference_docname - }, - } - ) - - frappe.local.flags.redirect_location = redirect_flow.redirect_url - except Exception: - frappe.log_error(_("GoCardless Payment Error")) - frappe.local.flags.redirect_location = "payment-failed" - raise frappe.Redirect - - raise frappe.Redirect - - -def redirect_to_invalid_link(): - frappe.redirect_to_message(_("Invalid link"), _("This link is not valid.
Please contact us.")) - frappe.local.flags.redirect_location = frappe.local.response.location - raise frappe.Redirect - - -class PrefilledCustomer: - def __init__(self, reference_document, context): - self.reference = reference_document - self.context = context - customer = self.reference.customer if hasattr(self.reference, 'customer') else self.reference.get("customer") - self.customer = frappe.get_doc("Customer", customer) - self.customer_address = {} - self.primary_contact = {} - - def get(self): - self.get_customer_address() - self.get_primary_contact() - email = self.primary_contact.get("email_id") or self.context.payer_email or frappe.session.user - - return { - "company_name": self.customer.customer_name, - "given_name": self.primary_contact.get("first_name") or "", - "family_name": self.primary_contact.get("last_name") or "", - "email": email if check_format(email) else "", - "address_line1": self.customer_address.address_line1 or "", - "address_line2": self.customer_address.address_line2 or "", - "city": self.customer_address.city or "", - "postal_code": self.customer_address.pincode or "", - "country_code": frappe.db.get_value("Country", self.customer_address.country, "code") or "", - } - - def get_customer_address(self): - customer_address_name = None - if self.reference.doctype == "Subscription": - customer_address_name = frappe.db.get_value( - "Customer", self.customer.name, "customer_primary_address" - ) - else: - customer_address_name = self.reference.get("customer_address") - - self.customer_address = ( - frappe.get_doc("Address", customer_address_name) if customer_address_name else frappe._dict() - ) - - def get_primary_contact(self): - if self.customer.customer_primary_contact: - self.primary_contact = frappe.db.get_value( - "Contact", - self.customer.customer_primary_contact, - ["first_name", "last_name", "email_id"], - as_dict=True, - ) - else: - get_default_contact(self.customer.doctype, self.customer.name) diff --git a/erpnext/templates/pages/integrations/gocardless_confirmation.html b/erpnext/templates/pages/integrations/gocardless_confirmation.html deleted file mode 100644 index 2f7fb4b2d32..00000000000 --- a/erpnext/templates/pages/integrations/gocardless_confirmation.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %} Payment {% endblock %} - -{%- block header -%}{% endblock %} - -{%- block page_content -%} -
-

- {{ _("Payment Confirmation") }} -

-
- -{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/pages/integrations/gocardless_confirmation.py b/erpnext/templates/pages/integrations/gocardless_confirmation.py deleted file mode 100644 index 8b13166daf5..00000000000 --- a/erpnext/templates/pages/integrations/gocardless_confirmation.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2023, Dokos SAS and Contributors -# License: See license.txt - -import frappe -from frappe import _ -from payments.utils.utils import get_gateway_controller - -EXPECTED_KEYS = ("redirect_flow_id", "reference_doctype", "reference_docname") - - -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] - - gateway_controller = frappe.get_doc( - "GoCardless Settings", - get_gateway_controller(context.reference_doctype, context.reference_docname), - ) - - try: - redirect_flow = gateway_controller.client.redirect_flows.complete( - context.redirect_flow_id, params={"session_token": f"{context.reference_doctype}&{context.reference_docname}"} - ) - - reference_document = frappe.get_doc(context.reference_doctype, context.reference_docname) - payment = gateway_controller.handle_redirect_flow(redirect_flow, reference_document) - - reference_document.run_method("on_payment_authorized", status="Pending", reference_no=payment) - - frappe.local.flags.redirect_location = "/payment-success" - except Exception: - frappe.log_error(_("GoCardless Payment Error")) - frappe.local.flags.redirect_location = "payment-failed" - raise frappe.Redirect - - raise frappe.Redirect - - else: - frappe.redirect_to_message(_("Invalid link"), _("This link is not valid.
Please contact us.")) - frappe.local.flags.redirect_location = frappe.local.response.location - raise frappe.Redirect -- GitLab From 05d9852b954559c7059380528aa9ba345de90bea Mon Sep 17 00:00:00 2001 From: Charles-Henri Decultot Date: Tue, 17 Oct 2023 16:00:01 +0200 Subject: [PATCH 12/12] fix: method path --- .../page/bank_reconciliation/gocardless_reconciliation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py index 148f8e6af02..1df9868067f 100644 --- a/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py +++ b/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py @@ -5,9 +5,9 @@ import re import frappe +from payments.payment_gateways.doctype.gocardless_settings.api import GoCardlessPayouts from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import BankReconciliation -from erpnext.erpnext_integrations.doctype.gocardless_settings.api import GoCardlessPayouts def reconcile_gocardless_payouts(bank_transactions): -- GitLab