From 0b86b1baca3cd6ba4001f3a4ec747a9aa49d569a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 8 Dec 2022 16:40:13 +0530 Subject: [PATCH] refactor: make payments app a soft dependency (#33245) refactor: make payment app a soft dependency --- .github/helper/site_config_mariadb.json | 2 +- .../payment_gateway_account.js | 1 + .../doctype/payment_request/payment_request.py | 15 +++++++++++---- .../subscription_plan/subscription_plan.js | 6 +++++- .../e_commerce_settings/e_commerce_settings.js | 6 ++++++ .../gocardless_settings/gocardless_settings.js | 3 +++ .../gocardless_settings/gocardless_settings.json | 3 +-- .../gocardless_settings/gocardless_settings.py | 6 +++++- .../doctype/mpesa_settings/mpesa_settings.js | 2 ++ .../doctype/mpesa_settings/mpesa_settings.py | 5 ++++- .../erpnext_integrations/stripe_integration.py | 9 ++++++++- erpnext/hooks.py | 1 - erpnext/public/js/utils.js | 12 +++++++++++- erpnext/utilities/__init__.py | 16 ++++++++++++++++ 14 files changed, 74 insertions(+), 13 deletions(-) diff --git a/.github/helper/site_config_mariadb.json b/.github/helper/site_config_mariadb.json index 49e7fcf7da9..8c86f73729f 100644 --- a/.github/helper/site_config_mariadb.json +++ b/.github/helper/site_config_mariadb.json @@ -11,6 +11,6 @@ "root_login": "root", "root_password": "root", "host_name": "http://test_site:8000", - "install_apps": ["erpnext"], + "install_apps": ["payments", "erpnext"], "throttle_user_limit": 100 } diff --git a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.js b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.js index 8f09bc36912..aff067eab89 100644 --- a/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.js +++ b/erpnext/accounts/doctype/payment_gateway_account/payment_gateway_account.js @@ -3,6 +3,7 @@ frappe.ui.form.on('Payment Gateway Account', { refresh(frm) { + erpnext.utils.check_payments_app(); if(!frm.doc.__islocal) { frm.set_df_property('payment_gateway', 'read_only', 1); } diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 8665b709565..d82083cea05 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -9,7 +9,6 @@ from frappe import _ from frappe.model.document import Document from frappe.utils import flt, get_url, nowdate from frappe.utils.background_jobs import enqueue -from payments.utils import get_payment_gateway_controller from erpnext.accounts.doctype.payment_entry.payment_entry import ( get_company_defaults, @@ -19,6 +18,14 @@ from erpnext.accounts.doctype.subscription_plan.subscription_plan import get_pla from erpnext.accounts.party import get_party_account, get_party_bank_account from erpnext.accounts.utils import get_account_currency from erpnext.erpnext_integrations.stripe_integration import create_stripe_subscription +from erpnext.utilities import payment_app_import_guard + + +def _get_payment_gateway_controller(*args, **kwargs): + with payment_app_import_guard(): + from payments.utils import get_payment_gateway_controller + + return get_payment_gateway_controller(*args, **kwargs) class PaymentRequest(Document): @@ -107,7 +114,7 @@ class PaymentRequest(Document): self.request_phone_payment() def request_phone_payment(self): - controller = get_payment_gateway_controller(self.payment_gateway) + controller = _get_payment_gateway_controller(self.payment_gateway) request_amount = self.get_request_amount() payment_record = dict( @@ -156,7 +163,7 @@ class PaymentRequest(Document): def payment_gateway_validation(self): try: - controller = get_payment_gateway_controller(self.payment_gateway) + controller = _get_payment_gateway_controller(self.payment_gateway) if hasattr(controller, "on_payment_request_submission"): return controller.on_payment_request_submission(self) else: @@ -189,7 +196,7 @@ class PaymentRequest(Document): ) data.update({"company": frappe.defaults.get_defaults().company}) - controller = get_payment_gateway_controller(self.payment_gateway) + controller = _get_payment_gateway_controller(self.payment_gateway) controller.validate_transaction_currency(self.currency) if hasattr(controller, "validate_minimum_transaction_amount"): diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.js b/erpnext/accounts/doctype/subscription_plan/subscription_plan.js index 7d6f2aed100..00727f103f9 100644 --- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.js +++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.js @@ -5,5 +5,9 @@ frappe.ui.form.on('Subscription Plan', { price_determination: function(frm) { frm.toggle_reqd("cost", frm.doc.price_determination === 'Fixed rate'); frm.toggle_reqd("price_list", frm.doc.price_determination === 'Based on price list'); - } + }, + + subscription_plan: function (frm) { + erpnext.utils.check_payments_app(); + }, }); diff --git a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.js b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.js index 69b9cfaa687..c37fa2f6eae 100644 --- a/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.js +++ b/erpnext/e_commerce/doctype/e_commerce_settings/e_commerce_settings.js @@ -48,5 +48,11 @@ frappe.ui.form.on("E Commerce Settings", { frm.set_value('default_customer_group', ''); frm.set_value('quotation_series', ''); } + }, + + enable_checkout: function(frm) { + if (frm.doc.enable_checkout) { + erpnext.utils.check_payments_app(); + } } }); diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js index b649d9d6cc9..241129719b8 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js +++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js @@ -2,4 +2,7 @@ // 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 index 9738106a30d..cca36536ac4 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json +++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json @@ -173,7 +173,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-02-12 14:18:47.209114", + "modified": "2022-02-12 14:18:47.209114", "modified_by": "Administrator", "module": "ERPNext Integrations", "name": "GoCardless Settings", @@ -201,7 +201,6 @@ "write": 1 } ], - "quick_entry": 1, "read_only": 0, "read_only_onload": 0, "show_name_in_global_search": 0, diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py index f9a293fc30e..4a29a6a21de 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py +++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py @@ -10,7 +10,8 @@ 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 payments.utils import create_payment_gateway + +from erpnext.utilities import payment_app_import_guard class GoCardlessSettings(Document): @@ -30,6 +31,9 @@ class GoCardlessSettings(Document): 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 ) diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js index 7c8ae5c8023..447d720ca24 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.js @@ -7,6 +7,8 @@ frappe.ui.form.on('Mpesa Settings', { }, refresh: function(frm) { + erpnext.utils.check_payments_app(); + frappe.realtime.on("refresh_mpesa_dashboard", function(){ frm.reload_doc(); frm.events.setup_account_balance_html(frm); diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py index b5347838647..a298e11eaf5 100644 --- a/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py +++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/mpesa_settings.py @@ -9,13 +9,13 @@ from frappe import _ from frappe.integrations.utils import create_request_log from frappe.model.document import Document from frappe.utils import call_hook_method, fmt_money, get_request_site_address -from payments.utils import create_payment_gateway from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_connector import MpesaConnector from erpnext.erpnext_integrations.doctype.mpesa_settings.mpesa_custom_fields import ( create_custom_pos_fields, ) from erpnext.erpnext_integrations.utils import create_mode_of_payment +from erpnext.utilities import payment_app_import_guard class MpesaSettings(Document): @@ -30,6 +30,9 @@ class MpesaSettings(Document): ) def on_update(self): + with payment_app_import_guard(): + from payments.utils import create_payment_gateway + create_custom_pos_fields() create_payment_gateway( "Mpesa-" + self.payment_gateway_name, diff --git a/erpnext/erpnext_integrations/stripe_integration.py b/erpnext/erpnext_integrations/stripe_integration.py index 2d7e8a5d31e..634e5c2e89f 100644 --- a/erpnext/erpnext_integrations/stripe_integration.py +++ b/erpnext/erpnext_integrations/stripe_integration.py @@ -2,12 +2,16 @@ # For license information, please see license.txt import frappe -import stripe from frappe import _ from frappe.integrations.utils import create_request_log +from erpnext.utilities import payment_app_import_guard + def create_stripe_subscription(gateway_controller, data): + with payment_app_import_guard(): + import stripe + stripe_settings = frappe.get_doc("Stripe Settings", gateway_controller) stripe_settings.data = frappe._dict(data) @@ -35,6 +39,9 @@ def create_stripe_subscription(gateway_controller, data): def create_subscription_on_stripe(stripe_settings): + with payment_app_import_guard(): + import stripe + items = [] for payment_plan in stripe_settings.payment_plans: plan = frappe.db.get_value("Subscription Plan", payment_plan.plan, "product_price_id") diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 92601b3444e..fd19d2585cc 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -8,7 +8,6 @@ app_email = "info@erpnext.com" app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" app_logo_url = "/assets/erpnext/images/erpnext-logo.svg" -required_apps = ["payments"] develop_version = "14.x.x-develop" diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 6d64625270b..d37b7bb43b3 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -333,8 +333,18 @@ $.extend(erpnext.utils, { } frappe.ui.form.make_quick_entry(doctype, null, null, new_doc); }); - } + }, + // check if payments app is installed on site, if not warn user. + check_payments_app: () => { + if (frappe.boot.versions && !frappe.boot.versions.payments) { + const marketplace_link = 'Marketplace' + const github_link = 'GitHub' + const msg = __("payments app is not installed. Please install it from {0} or {1}", [marketplace_link, github_link]) + frappe.msgprint(msg); + } + + }, }); erpnext.utils.select_alternate_items = function(opts) { diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py index c2b4229f171..24bfdc63af6 100644 --- a/erpnext/utilities/__init__.py +++ b/erpnext/utilities/__init__.py @@ -1,6 +1,9 @@ ## temp utility +from contextlib import contextmanager + import frappe +from frappe import _ from frappe.utils import cstr from erpnext.utilities.activation import get_level @@ -35,3 +38,16 @@ def get_site_info(site_info): domain = frappe.get_cached_value("Company", cstr(company), "domain") return {"company": company, "domain": domain, "activation": get_level()} + + +@contextmanager +def payment_app_import_guard(): + marketplace_link = 'Marketplace' + github_link = 'GitHub' + msg = _("payments app is not installed. Please install it from {} or {}").format( + marketplace_link, github_link + ) + try: + yield + except ImportError: + frappe.throw(msg, title=_("Missing Payments App"))