diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 00000000..1f225527
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,130 @@
+{
+ "env": {
+ "browser": true,
+ "node": true,
+ "es2022": true
+ },
+ "parserOptions": {
+ "sourceType": "module"
+ },
+ "extends": "eslint:recommended",
+ "rules": {
+ "indent": "off",
+ "brace-style": "off",
+ "no-mixed-spaces-and-tabs": "off",
+ "no-useless-escape": "off",
+ "space-unary-ops": ["error", { "words": true }],
+ "linebreak-style": "off",
+ "quotes": ["off"],
+ "semi": "off",
+ "camelcase": "off",
+ "no-unused-vars": "off",
+ "no-console": ["warn"],
+ "no-extra-boolean-cast": ["off"],
+ "no-control-regex": ["off"]
+ },
+ "root": true,
+ "globals": {
+ "frappe": true,
+ "Vue": true,
+ "SetVueGlobals": true,
+ "erpnext": true,
+ "hub": true,
+ "$": true,
+ "jQuery": true,
+ "moment": true,
+ "hljs": true,
+ "Awesomplete": true,
+ "CalHeatMap": true,
+ "Sortable": true,
+ "Showdown": true,
+ "Taggle": true,
+ "Gantt": true,
+ "Slick": true,
+ "PhotoSwipe": true,
+ "PhotoSwipeUI_Default": true,
+ "fluxify": true,
+ "io": true,
+ "c3": true,
+ "__": true,
+ "_p": true,
+ "_f": true,
+ "repl": true,
+ "Class": true,
+ "locals": true,
+ "cint": true,
+ "cstr": true,
+ "cur_frm": true,
+ "cur_dialog": true,
+ "cur_page": true,
+ "cur_list": true,
+ "cur_tree": true,
+ "cur_pos": true,
+ "msg_dialog": true,
+ "is_null": true,
+ "in_list": true,
+ "has_common": true,
+ "posthog": true,
+ "has_words": true,
+ "validate_email": true,
+ "open_web_template_values_editor": true,
+ "get_number_format": true,
+ "format_number": true,
+ "format_currency": true,
+ "round_based_on_smallest_currency_fraction": true,
+ "roundNumber": true,
+ "comment_when": true,
+ "replace_newlines": true,
+ "open_url_post": true,
+ "toTitle": true,
+ "lstrip": true,
+ "strip": true,
+ "strip_html": true,
+ "replace_all": true,
+ "flt": true,
+ "precision": true,
+ "md5": true,
+ "CREATE": true,
+ "AMEND": true,
+ "CANCEL": true,
+ "copy_dict": true,
+ "get_number_format_info": true,
+ "print_table": true,
+ "Layout": true,
+ "web_form_settings": true,
+ "$c": true,
+ "$a": true,
+ "$i": true,
+ "$bg": true,
+ "$y": true,
+ "$c_obj": true,
+ "$c_obj_csv": true,
+ "refresh_many": true,
+ "refresh_field": true,
+ "toggle_field": true,
+ "get_field_obj": true,
+ "get_query_params": true,
+ "unhide_field": true,
+ "hide_field": true,
+ "set_field_options": true,
+ "getCookie": true,
+ "getCookies": true,
+ "get_url_arg": true,
+ "get_server_fields": true,
+ "set_multiple": true,
+ "QUnit": true,
+ "Chart": true,
+ "Cypress": true,
+ "cy": true,
+ "describe": true,
+ "expect": true,
+ "it": true,
+ "context": true,
+ "before": true,
+ "beforeEach": true,
+ "onScan": true,
+ "extend_cscript": true,
+ "localforage": true,
+ "Plaid": true
+ }
+}
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 00000000..56274db0
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,15 @@
+# Since version 2.23 (released in August 2019), git-blame has a feature
+# to ignore or bypass certain commits.
+#
+# This file contains a list of commits that are not likely what you
+# are looking for in a blame, such as mass reformatting or renaming.
+# You can set this file as a default ignore file for blame by running
+# the following command.
+#
+# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
+
+# pre-commit formatting ruff, eslint, prettier (automated)
+63a4acf6c9fe9657fa6d7ad659465b0d5ef3d73f
+
+# pre-commit formatting ruff, eslint, prettier (manual fixup)
+cecf0bec9de2dcd176fc632e8a5348ab2f491cbe
\ No newline at end of file
diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 00000000..65bc68f2
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,4 @@
+# Any python files modifed but no test files modified
+needs-tests:
+- any: ['payments/**/*.py']
+ all: ['!payments/**/test*.py']
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f552a81d..e9f5b27e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -20,24 +20,47 @@ repos:
- id: check-yaml
- id: debug-statements
- - repo: https://github.com/asottile/pyupgrade
- rev: v2.34.0
+ - repo: https://github.com/pre-commit/mirrors-prettier
+ rev: v2.7.1
hooks:
- - id: pyupgrade
- args: ['--py310-plus']
+ - id: prettier
+ types_or: [javascript, vue, scss]
+ # Ignore any files that might contain jinja / bundles
+ exclude: |
+ (?x)^(
+ payments/public/dist/.*|
+ cypress/.*|
+ .*node_modules.*|
+ payments/templates/includes/.*
+ )$
- - repo: https://github.com/adityahase/black
- rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119
+ - repo: https://github.com/pre-commit/mirrors-eslint
+ rev: v8.44.0
hooks:
- - id: black
- additional_dependencies: ['click==8.0.4']
+ - id: eslint
+ types_or: [javascript]
+ args: ['--quiet']
+ # Ignore any files that might contain jinja / bundles
+ exclude: |
+ (?x)^(
+ payments/public/dist/.*|
+ cypress/.*|
+ .*node_modules.*|
+ payments/templates/includes/.*
+ )$
- - repo: https://github.com/PyCQA/flake8
- rev: 6.0.0
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.2.0
hooks:
- - id: flake8
- additional_dependencies: ['flake8-bugbear',]
- args: ['--config', '.github/helper/flake8.conf']
+ - id: ruff
+ name: "Run ruff import sorter"
+ args: ["--select=I", "--fix"]
+
+ - id: ruff
+ name: "Run ruff linter"
+
+ - id: ruff-format
+ name: "Run ruff formatter"
ci:
autoupdate_schedule: weekly
diff --git a/commitlint.config.js b/commitlint.config.js
index 8847564e..bd5cebce 100644
--- a/commitlint.config.js
+++ b/commitlint.config.js
@@ -1,25 +1,25 @@
module.exports = {
- parserPreset: 'conventional-changelog-conventionalcommits',
- rules: {
- 'subject-empty': [2, 'never'],
- 'type-case': [2, 'always', 'lower-case'],
- 'type-empty': [2, 'never'],
- 'type-enum': [
- 2,
- 'always',
- [
- 'build',
- 'chore',
- 'ci',
- 'docs',
- 'feat',
- 'fix',
- 'perf',
- 'refactor',
- 'revert',
- 'style',
- 'test',
- ],
- ],
- },
+ parserPreset: "conventional-changelog-conventionalcommits",
+ rules: {
+ "subject-empty": [2, "never"],
+ "type-case": [2, "always", "lower-case"],
+ "type-empty": [2, "never"],
+ "type-enum": [
+ 2,
+ "always",
+ [
+ "build",
+ "chore",
+ "ci",
+ "docs",
+ "feat",
+ "fix",
+ "perf",
+ "refactor",
+ "revert",
+ "style",
+ "test",
+ ],
+ ],
+ },
};
diff --git a/payments/payment_gateways/doctype/braintree_settings/braintree_settings.js b/payments/payment_gateways/doctype/braintree_settings/braintree_settings.js
index c844022c..f9d77bf7 100644
--- a/payments/payment_gateways/doctype/braintree_settings/braintree_settings.js
+++ b/payments/payment_gateways/doctype/braintree_settings/braintree_settings.js
@@ -1,6 +1,4 @@
// Copyright (c) 2018, Frappe Technologies and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Braintree Settings', {
-
-});
+frappe.ui.form.on("Braintree Settings", {});
diff --git a/payments/payment_gateways/doctype/braintree_settings/braintree_settings.py b/payments/payment_gateways/doctype/braintree_settings/braintree_settings.py
index 717443e8..5c0fe801 100644
--- a/payments/payment_gateways/doctype/braintree_settings/braintree_settings.py
+++ b/payments/payment_gateways/doctype/braintree_settings/braintree_settings.py
@@ -14,7 +14,7 @@
class BraintreeSettings(Document):
- supported_currencies = [
+ supported_currencies = (
"AED",
"AMD",
"AOA",
@@ -150,7 +150,7 @@ class BraintreeSettings(Document):
"ZAR",
"ZMK",
"ZWD",
- ]
+ )
def validate(self):
if not self.flags.ignore_mandatory:
diff --git a/payments/payment_gateways/doctype/gocardless_mandate/gocardless_mandate.js b/payments/payment_gateways/doctype/gocardless_mandate/gocardless_mandate.js
index 37f9f7b9..9f8a22bb 100644
--- a/payments/payment_gateways/doctype/gocardless_mandate/gocardless_mandate.js
+++ b/payments/payment_gateways/doctype/gocardless_mandate/gocardless_mandate.js
@@ -1,5 +1,4 @@
// Copyright (c) 2018, Frappe Technologies and contributors
// For license information, please see license.txt
-frappe.ui.form.on('GoCardless Mandate', {
-});
+frappe.ui.form.on("GoCardless Mandate", {});
diff --git a/payments/payment_gateways/doctype/gocardless_settings/__init__.py b/payments/payment_gateways/doctype/gocardless_settings/__init__.py
index 65be5993..d8f8a3d3 100644
--- a/payments/payment_gateways/doctype/gocardless_settings/__init__.py
+++ b/payments/payment_gateways/doctype/gocardless_settings/__init__.py
@@ -34,7 +34,7 @@ def set_status(event):
def set_mandate_status(event):
mandates = []
- if isinstance(event["links"], (list,)):
+ if isinstance(event["links"], list):
for link in event["links"]:
mandates.append(link["mandate"])
else:
diff --git a/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.js b/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.js
index ef1b97f6..a4db118d 100644
--- a/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.js
+++ b/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.js
@@ -5,4 +5,4 @@
// refresh(frm) {
// },
-// });
\ No newline at end of file
+// });
diff --git a/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.py b/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.py
index ac6b83a9..4abb7e97 100644
--- a/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.py
+++ b/payments/payment_gateways/doctype/gocardless_settings/gocardless_settings.py
@@ -13,7 +13,7 @@
class GoCardlessSettings(Document):
- supported_currencies = ["EUR", "DKK", "GBP", "SEK", "AUD", "NZD", "CAD", "USD"]
+ supported_currencies = ("EUR", "DKK", "GBP", "SEK", "AUD", "NZD", "CAD", "USD")
def validate(self):
self.initialize_client()
@@ -21,9 +21,7 @@ def validate(self):
def initialize_client(self):
self.environment = self.get_environment()
try:
- self.client = gocardless_pro.Client(
- access_token=self.access_token, environment=self.environment
- )
+ self.client = gocardless_pro.Client(access_token=self.access_token, environment=self.environment)
return self.client
except Exception as e:
frappe.throw(e)
@@ -64,7 +62,6 @@ def on_payment_request_submission(self, data):
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"
@@ -124,9 +121,7 @@ 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")
- )
+ reference_doc = frappe.get_doc(self.data.get("reference_doctype"), self.data.get("reference_docname"))
self.initialize_client()
try:
@@ -172,7 +167,7 @@ def create_charge_on_gocardless(self):
frappe.log_error("Gocardless payment failed")
self.integration_request.db_set("error", payment.status, update_modified=False)
- except Exception as e:
+ except Exception:
frappe.log_error("GoCardless Payment Error")
if self.flags.status_changed_to == "Completed":
diff --git a/payments/payment_gateways/doctype/mpesa_settings/mpesa_connector.py b/payments/payment_gateways/doctype/mpesa_settings/mpesa_connector.py
index 7eb8b9c0..ce6df833 100644
--- a/payments/payment_gateways/doctype/mpesa_settings/mpesa_connector.py
+++ b/payments/payment_gateways/doctype/mpesa_settings/mpesa_connector.py
@@ -119,10 +119,8 @@ def stk_push(
errorMessage(str): This is a predefined code that indicates the reason for request failure.
"""
- time = (
- str(datetime.datetime.now()).split(".")[0].replace("-", "").replace(" ", "").replace(":", "")
- )
- password = f"{str(business_shortcode)}{str(passcode)}{time}"
+ time = str(datetime.datetime.now()).split(".")[0].replace("-", "").replace(" ", "").replace(":", "")
+ password = f"{business_shortcode!s}{passcode!s}{time}"
encoded = base64.b64encode(bytes(password, encoding="utf8"))
payload = {
"BusinessShortCode": business_shortcode,
@@ -135,9 +133,7 @@ def stk_push(
"CallBackURL": callback_url,
"AccountReference": reference_code,
"TransactionDesc": description,
- "TransactionType": "CustomerPayBillOnline"
- if self.env == "sandbox"
- else "CustomerBuyGoodsOnline",
+ "TransactionType": "CustomerPayBillOnline" if self.env == "sandbox" else "CustomerBuyGoodsOnline",
}
headers = {
"Authorization": f"Bearer {self.authentication_token}",
diff --git a/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.js b/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.js
index 9d625736..491223da 100644
--- a/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.js
+++ b/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.js
@@ -1,36 +1,38 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Mpesa Settings', {
- onload_post_render: function(frm) {
- frm.events.setup_account_balance_html(frm);
- },
+frappe.ui.form.on("Mpesa Settings", {
+ onload_post_render: function (frm) {
+ frm.events.setup_account_balance_html(frm);
+ },
- refresh: function(frm) {
- frappe.realtime.on("refresh_mpesa_dashboard", function(){
- frm.reload_doc();
- frm.events.setup_account_balance_html(frm);
- });
- },
+ refresh: function (frm) {
+ frappe.realtime.on("refresh_mpesa_dashboard", function () {
+ frm.reload_doc();
+ frm.events.setup_account_balance_html(frm);
+ });
+ },
- get_account_balance: function(frm) {
- if (!frm.doc.initiator_name && !frm.doc.security_credential) {
- frappe.throw(__("Please set the initiator name and the security credential"));
- }
- frappe.call({
- method: "get_account_balance_info",
- doc: frm.doc
- });
- },
+ get_account_balance: function (frm) {
+ if (!frm.doc.initiator_name && !frm.doc.security_credential) {
+ frappe.throw(
+ __("Please set the initiator name and the security credential")
+ );
+ }
+ frappe.call({
+ method: "get_account_balance_info",
+ doc: frm.doc,
+ });
+ },
- setup_account_balance_html: function(frm) {
- if (!frm.doc.account_balance) return;
- $("div").remove(".form-dashboard-section.custom");
- frm.dashboard.add_section(
- frappe.render_template('account_balance', {
- data: JSON.parse(frm.doc.account_balance)
- })
- );
- frm.dashboard.show();
- }
+ setup_account_balance_html: function (frm) {
+ if (!frm.doc.account_balance) return;
+ $("div").remove(".form-dashboard-section.custom");
+ frm.dashboard.add_section(
+ frappe.render_template("account_balance", {
+ data: JSON.parse(frm.doc.account_balance),
+ })
+ );
+ frm.dashboard.show();
+ },
});
diff --git a/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.py b/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.py
index 43d5348b..97e9aacc 100644
--- a/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.py
+++ b/payments/payment_gateways/doctype/mpesa_settings/mpesa_settings.py
@@ -18,7 +18,7 @@
class MpesaSettings(Document):
- supported_currencies = ["KES"]
+ supported_currencies = ("KES",)
def validate_transaction_currency(self, currency):
if currency not in self.supported_currencies:
@@ -51,7 +51,7 @@ def request_for_payment(self, **kwargs):
args = frappe._dict(kwargs)
request_amounts = self.split_request_amount_according_to_transaction_limit(args)
- for i, amount in enumerate(request_amounts):
+ for _i, amount in enumerate(request_amounts):
args.request_amount = amount
if frappe.flags.in_test:
from payments.payment_gateways.doctype.mpesa_settings.test_mpesa_settings import (
@@ -104,8 +104,8 @@ def get_account_balance_info(self):
def handle_api_response(self, global_id, request_dict, response):
"""Response received from API calls returns a global identifier for each transaction, this code is returned during the callback."""
# check error response
- if getattr(response, "requestId"):
- req_name = getattr(response, "requestId")
+ if response.requestId:
+ req_name = response.requestId
error = response
else:
# global checkout id used as request name
@@ -116,7 +116,7 @@ def handle_api_response(self, global_id, request_dict, response):
create_request_log(request_dict, "Host", "Mpesa", req_name, error)
if error:
- frappe.throw(_(getattr(response, "errorMessage")), title=_("Transaction Error"))
+ frappe.throw(_(response.errorMessage), title=_("Transaction Error"))
def generate_stk_push(**kwargs):
@@ -197,7 +197,7 @@ def verify_transaction(**kwargs):
)
total_paid = amount + sum(completed_payments)
- mpesa_receipts = ", ".join(mpesa_receipts + [mpesa_receipt])
+ mpesa_receipts = ", ".join([*mpesa_receipts, mpesa_receipt])
if total_paid >= pr.grand_total:
pr.run_method("on_payment_authorized", "Completed")
@@ -318,9 +318,7 @@ def process_balance_info(**kwargs):
)
except Exception:
request.handle_failure(account_balance_response)
- frappe.log_error(
- title="Mpesa Account Balance Processing Error", message=account_balance_response
- )
+ frappe.log_error(title="Mpesa Account Balance Processing Error", message=account_balance_response)
else:
request.handle_failure(account_balance_response)
diff --git a/payments/payment_gateways/doctype/mpesa_settings/test_mpesa_settings.py b/payments/payment_gateways/doctype/mpesa_settings/test_mpesa_settings.py
index aab37d93..c0eb227e 100644
--- a/payments/payment_gateways/doctype/mpesa_settings/test_mpesa_settings.py
+++ b/payments/payment_gateways/doctype/mpesa_settings/test_mpesa_settings.py
@@ -5,17 +5,16 @@
from json import dumps
import frappe
-
from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_customer
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
-from erpnext.stock.doctype.item.test_item import make_item
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
+from erpnext.stock.doctype.item.test_item import make_item
from payments.payment_gateways.doctype.mpesa_settings.mpesa_settings import (
+ create_mode_of_payment,
process_balance_info,
verify_transaction,
)
-from payments.payment_gateways.doctype.mpesa_settings.mpesa_settings import create_mode_of_payment
class TestMpesaSettings(unittest.TestCase):
@@ -120,9 +119,7 @@ def test_processing_of_callback_payload(self):
pluck="name",
)
- callback_response = get_payment_callback_payload(
- Amount=500, CheckoutRequestID=integration_req_ids[0]
- )
+ callback_response = get_payment_callback_payload(Amount=500, CheckoutRequestID=integration_req_ids[0])
verify_transaction(**callback_response)
# test creation of integration request
integration_request = frappe.get_doc("Integration Request", integration_req_ids[0])
diff --git a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.js b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.js
index 63480bc9..9f8ad92a 100644
--- a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.js
+++ b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.js
@@ -1,8 +1,6 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt
-frappe.ui.form.on('PayPal Settings', {
- refresh: function(frm) {
-
- }
+frappe.ui.form.on("PayPal Settings", {
+ refresh: function (frm) {},
});
diff --git a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py
index 04943a5c..5bf4a2fb 100644
--- a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py
+++ b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py
@@ -79,7 +79,7 @@ def on_payment_authorized(payment_status):
class PayPalSettings(Document):
- supported_currencies = [
+ supported_currencies = (
"AUD",
"BRL",
"CAD",
@@ -105,14 +105,14 @@ class PayPalSettings(Document):
"THB",
"TRY",
"USD",
- ]
+ )
def __setup__(self):
- setattr(self, "use_sandbox", 0)
+ self.use_sandbox = 0
def setup_sandbox_env(self, token):
data = json.loads(frappe.db.get_value("Integration Request", token, "data"))
- setattr(self, "use_sandbox", cint(frappe._dict(data).use_sandbox) or 0)
+ self.use_sandbox = cint(frappe._dict(data).use_sandbox) or 0
def validate(self):
create_payment_gateway("PayPal")
@@ -171,7 +171,7 @@ def validate_paypal_credentails(self):
frappe.throw(_("Invalid payment gateway credentials"))
def get_payment_url(self, **kwargs):
- setattr(self, "use_sandbox", cint(kwargs.get("use_sandbox", 0)))
+ self.use_sandbox = cint(kwargs.get("use_sandbox", 0))
response = self.execute_set_express_checkout(**kwargs)
diff --git a/payments/payment_gateways/doctype/paytm_settings/paytm_settings.js b/payments/payment_gateways/doctype/paytm_settings/paytm_settings.js
index fe2ee7c9..e561698e 100644
--- a/payments/payment_gateways/doctype/paytm_settings/paytm_settings.js
+++ b/payments/payment_gateways/doctype/paytm_settings/paytm_settings.js
@@ -1,8 +1,14 @@
// Copyright (c) 2020, Frappe Technologies and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Paytm Settings', {
- refresh: function(frm) {
- frm.dashboard.set_headline(__("For more information, {0}.", [`${__('Click here')}`]));
- }
+frappe.ui.form.on("Paytm Settings", {
+ refresh: function (frm) {
+ frm.dashboard.set_headline(
+ __("For more information, {0}.", [
+ `${__(
+ "Click here"
+ )}`,
+ ])
+ );
+ },
});
diff --git a/payments/payment_gateways/doctype/paytm_settings/paytm_settings.py b/payments/payment_gateways/doctype/paytm_settings/paytm_settings.py
index 99e9f909..db879255 100644
--- a/payments/payment_gateways/doctype/paytm_settings/paytm_settings.py
+++ b/payments/payment_gateways/doctype/paytm_settings/paytm_settings.py
@@ -24,7 +24,7 @@
class PaytmSettings(Document):
- supported_currencies = ["INR"]
+ supported_currencies = ("INR",)
def validate(self):
create_payment_gateway("Paytm")
@@ -75,7 +75,6 @@ def get_paytm_config():
def get_paytm_params(payment_details, order_id, paytm_config):
-
# initialize a dictionary
paytm_params = dict()
@@ -127,9 +126,7 @@ def verify_transaction(**paytm_params):
http_status_code=401,
indicator_color="red",
)
- frappe.log_error(
- "Order unsuccessful. Failed Response:" + cstr(paytm_params), "Paytm Payment Failed"
- )
+ frappe.log_error("Order unsuccessful. Failed Response:" + cstr(paytm_params), "Paytm Payment Failed")
def verify_transaction_status(paytm_config, order_id):
diff --git a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.js b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.js
index 6915c5c5..00a5ec9c 100644
--- a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.js
+++ b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.js
@@ -1,8 +1,6 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Razorpay Settings', {
- refresh: function(frm) {
-
- }
-});
\ No newline at end of file
+frappe.ui.form.on("Razorpay Settings", {
+ refresh: function (frm) {},
+});
diff --git a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py
index ebf16056..7394456f 100644
--- a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py
+++ b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py
@@ -79,7 +79,7 @@ def on_payment_authorized(payment_status):
class RazorpaySettings(Document):
- supported_currencies = ["INR"]
+ supported_currencies = ("INR",)
def init_client(self):
if self.api_key:
@@ -251,8 +251,8 @@ def create_request(self, data):
def authorize_payment(self):
"""
- An authorization is performed when user’s payment details are successfully authenticated by the bank.
- The money is deducted from the customer’s account, but will not be transferred to the merchant’s account
+ An authorization is performed when user's payment details are successfully authenticated by the bank.
+ The money is deducted from the customer's account, but will not be transferred to the merchant's account
until it is explicitly captured by merchant.
"""
data = json.loads(self.integration_request.data)
@@ -306,8 +306,8 @@ def authorize_payment(self):
if custom_redirect_to:
redirect_to = custom_redirect_to
- redirect_url = "payment-success?doctype={}&docname={}".format(
- self.data.reference_doctype, self.data.reference_docname
+ redirect_url = (
+ f"payment-success?doctype={self.data.reference_doctype}&docname={self.data.reference_docname}"
)
else:
redirect_url = "payment-failed"
@@ -341,7 +341,7 @@ def cancel_subscription(self, subscription_id):
settings = self.get_settings({})
try:
- resp = make_post_request(
+ make_post_request(
f"https://api.razorpay.com/v1/subscriptions/{subscription_id}/cancel",
auth=(settings.api_key, settings.api_secret),
)
@@ -393,7 +393,9 @@ def capture_payment(is_sandbox=False, sanbox_response=None):
if resp.get("status") == "authorized":
resp = make_post_request(
- "https://api.razorpay.com/v1/payments/{}/capture".format(data.get("razorpay_payment_id")),
+ "https://api.razorpay.com/v1/payments/{}/capture".format(
+ data.get("razorpay_payment_id")
+ ),
auth=(settings.api_key, settings.api_secret),
data={"amount": data.get("amount")},
)
diff --git a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.js b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.js
index 578ae949..31636949 100644
--- a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.js
+++ b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.js
@@ -1,8 +1,6 @@
// Copyright (c) 2017, Frappe Technologies and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Stripe Settings', {
- refresh: function(frm) {
-
- }
+frappe.ui.form.on("Stripe Settings", {
+ refresh: function (frm) {},
});
diff --git a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py
index bb1bc677..ce3a1a02 100644
--- a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py
+++ b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py
@@ -1,6 +1,7 @@
# Copyright (c) 2017, Frappe Technologies and contributors
# License: MIT. See LICENSE
+from types import MappingProxyType
from urllib.parse import urlencode
import frappe
@@ -11,9 +12,27 @@
from payments.utils import create_payment_gateway
+currency_wise_minimum_charge_amount = {
+ "JPY": 50,
+ "MXN": 10,
+ "DKK": 2.50,
+ "HKD": 4.00,
+ "NOK": 3.00,
+ "SEK": 3.00,
+ "USD": 0.50,
+ "AUD": 0.50,
+ "BRL": 0.50,
+ "CAD": 0.50,
+ "CHF": 0.50,
+ "EUR": 0.50,
+ "GBP": 0.30,
+ "NZD": 0.50,
+ "SGD": 0.50,
+}
+
class StripeSettings(Document):
- supported_currencies = [
+ supported_currencies = (
"AED",
"ALL",
"ANG",
@@ -128,25 +147,9 @@ class StripeSettings(Document):
"XPF",
"YER",
"ZAR",
- ]
-
- currency_wise_minimum_charge_amount = {
- "JPY": 50,
- "MXN": 10,
- "DKK": 2.50,
- "HKD": 4.00,
- "NOK": 3.00,
- "SEK": 3.00,
- "USD": 0.50,
- "AUD": 0.50,
- "BRL": 0.50,
- "CAD": 0.50,
- "CHF": 0.50,
- "EUR": 0.50,
- "GBP": 0.30,
- "NZD": 0.50,
- "SGD": 0.50,
- }
+ )
+
+ currency_wise_minimum_charge_amount = MappingProxyType(currency_wise_minimum_charge_amount)
def on_update(self):
create_payment_gateway(
@@ -225,7 +228,7 @@ def create_charge_on_stripe(self):
receipt_email=self.data.payer_email,
)
- if charge.captured == True:
+ if charge.captured is True:
self.integration_request.db_set("status", "Completed", update_modified=False)
self.flags.status_changed_to = "Completed"
@@ -255,9 +258,7 @@ def finalize_request(self):
if custom_redirect_to:
redirect_to = custom_redirect_to
- redirect_url = "payment-success?doctype={}&docname={}".format(
- self.data.reference_doctype, self.data.reference_docname
- )
+ redirect_url = f"payment-success?doctype={self.data.reference_doctype}&docname={self.data.reference_docname}"
if self.redirect_url:
redirect_url = self.redirect_url
diff --git a/payments/payment_gateways/stripe_integration.py b/payments/payment_gateways/stripe_integration.py
index 35c63c55..2d7e8a5d 100644
--- a/payments/payment_gateways/stripe_integration.py
+++ b/payments/payment_gateways/stripe_integration.py
@@ -1,8 +1,8 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-import stripe
import frappe
+import stripe
from frappe import _
from frappe.integrations.utils import create_request_log
diff --git a/payments/payments/doctype/payment_gateway/payment_gateway.js b/payments/payments/doctype/payment_gateway/payment_gateway.js
index 0eff5a56..3e74b9cb 100644
--- a/payments/payments/doctype/payment_gateway/payment_gateway.js
+++ b/payments/payments/doctype/payment_gateway/payment_gateway.js
@@ -1,8 +1,6 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-frappe.ui.form.on('Payment Gateway', {
- refresh: function(frm) {
-
- }
+frappe.ui.form.on("Payment Gateway", {
+ refresh: function (frm) {},
});
diff --git a/payments/public/js/razorpay.js b/payments/public/js/razorpay.js
index c74d1be7..cf55b991 100644
--- a/payments/public/js/razorpay.js
+++ b/payments/public/js/razorpay.js
@@ -54,95 +54,110 @@ Razorpay Payment
frappe.provide("frappe.checkout");
-frappe.require('https://checkout.razorpay.com/v1/checkout.js').then(() => {
- frappe.checkout.razorpay = class RazorpayCheckout {
- constructor(opts) {
- Object.assign(this, opts);
- }
-
- init() {
- frappe.run_serially([
- () => this.get_key(),
- () => this.make_order(),
- () => this.prepare_options(),
- () => this.setup_handler(),
- () => this.show()
- ]);
- }
-
- show() {
- this.razorpay = new Razorpay(this.options);
- this.razorpay.once('ready', (response) => {
- this.on_open && this.on_open(response);
- })
- this.razorpay.open();
- }
-
- get_key() {
- return new Promise(resolve => {
- frappe.call("payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.get_api_key").then(res => {
- this.key = res.message;
- resolve(true);
- })
- });
- }
-
- make_order() {
- return new Promise(resolve => {
- frappe.call("payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.get_order", {
- doctype: this.doctype,
- docname: this.docname
- }).then(res => {
- this.order = res.message;
- resolve(true);
- })
- });
- }
-
- order_success(response) {
- frappe.call("payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.order_payment_success", {
- integration_request: this.order.integration_request,
- params: {
- razorpay_payment_id: response.razorpay_payment_id,
- razorpay_order_id: response.razorpay_order_id,
- razorpay_signature: response.razorpay_signature
- }
- })
- }
-
- order_fail(response) {
- frappe.call( "payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.order_payment_failure", {
- integration_request: this.order.integration_request,
- params: response
- })
- }
-
- prepare_options() {
- this.options = {
- "key": this.key,
- "amount": this.order.amount_due,
- "currency": this.order.currency,
- "name": this.name,
- "description": this.description,
- "image": this.image,
- "order_id": this.order.id,
- "prefill": this.prefill,
- "theme": this.theme,
- "modal": this.modal
- };
- }
-
- setup_handler() {
- this.options.handler = (response) => {
- if (response.error) {
- this.order_fail(response);
- this.on_fail && this.on_fail(response);
- }
- else if (response.razorpay_payment_id) {
- this.order_success(response);
- this.on_success && this.on_success(response);
- }
- }
- }
- }
+frappe.require("https://checkout.razorpay.com/v1/checkout.js").then(() => {
+ frappe.checkout.razorpay = class RazorpayCheckout {
+ constructor(opts) {
+ Object.assign(this, opts);
+ }
+
+ init() {
+ frappe.run_serially([
+ () => this.get_key(),
+ () => this.make_order(),
+ () => this.prepare_options(),
+ () => this.setup_handler(),
+ () => this.show(),
+ ]);
+ }
+
+ show() {
+ // eslint-disable-next-line no-undef
+ this.razorpay = new Razorpay(this.options);
+ this.razorpay.once("ready", (response) => {
+ this.on_open && this.on_open(response);
+ });
+ this.razorpay.open();
+ }
+
+ get_key() {
+ return new Promise((resolve) => {
+ frappe
+ .call(
+ "payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.get_api_key"
+ )
+ .then((res) => {
+ this.key = res.message;
+ resolve(true);
+ });
+ });
+ }
+
+ make_order() {
+ return new Promise((resolve) => {
+ frappe
+ .call(
+ "payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.get_order",
+ {
+ doctype: this.doctype,
+ docname: this.docname,
+ }
+ )
+ .then((res) => {
+ this.order = res.message;
+ resolve(true);
+ });
+ });
+ }
+
+ order_success(response) {
+ frappe.call(
+ "payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.order_payment_success",
+ {
+ integration_request: this.order.integration_request,
+ params: {
+ razorpay_payment_id: response.razorpay_payment_id,
+ razorpay_order_id: response.razorpay_order_id,
+ razorpay_signature: response.razorpay_signature,
+ },
+ }
+ );
+ }
+
+ order_fail(response) {
+ frappe.call(
+ "payments.payment_gateways.doctype.razorpay_settings.razorpay_settings.order_payment_failure",
+ {
+ integration_request: this.order.integration_request,
+ params: response,
+ }
+ );
+ }
+
+ prepare_options() {
+ this.options = {
+ key: this.key,
+ amount: this.order.amount_due,
+ currency: this.order.currency,
+ name: this.name,
+ description: this.description,
+ image: this.image,
+ order_id: this.order.id,
+ prefill: this.prefill,
+ theme: this.theme,
+ modal: this.modal,
+ };
+ }
+
+ setup_handler() {
+ this.options.handler = (response) => {
+ if (response.error) {
+ this.order_fail(response);
+ this.on_fail && this.on_fail(response);
+ } else if (response.razorpay_payment_id) {
+ this.order_success(response);
+ this.on_success && this.on_success(response);
+ }
+ };
+ }
+ };
});
diff --git a/payments/templates/pages/braintree_checkout.py b/payments/templates/pages/braintree_checkout.py
index 12b01369..a0dd968f 100644
--- a/payments/templates/pages/braintree_checkout.py
+++ b/payments/templates/pages/braintree_checkout.py
@@ -40,9 +40,7 @@ def get_context(context):
context["amount"] = flt(context["amount"])
gateway_controller = get_gateway_controller(context.reference_docname)
- context["header_img"] = frappe.db.get_value(
- "Braintree Settings", gateway_controller, "header_img"
- )
+ context["header_img"] = frappe.db.get_value("Braintree Settings", gateway_controller, "header_img")
else:
frappe.redirect_to_message(
diff --git a/payments/templates/pages/gocardless_checkout.py b/payments/templates/pages/gocardless_checkout.py
index fa780d23..89665995 100644
--- a/payments/templates/pages/gocardless_checkout.py
+++ b/payments/templates/pages/gocardless_checkout.py
@@ -38,9 +38,7 @@ def get_context(context):
context["amount"] = flt(context["amount"])
gateway_controller = get_gateway_controller(context.reference_docname)
- context["header_img"] = frappe.db.get_value(
- "GoCardless Settings", gateway_controller, "header_img"
- )
+ context["header_img"] = frappe.db.get_value("GoCardless Settings", gateway_controller, "header_img")
else:
frappe.redirect_to_message(
@@ -95,6 +93,6 @@ def check_mandate(data, reference_doctype, reference_docname):
return {"redirect_to": redirect_flow.redirect_url}
- except Exception as e:
+ except Exception:
frappe.log_error("GoCardless Payment Error")
return {"redirect_to": "payment-failed"}
diff --git a/payments/templates/pages/gocardless_confirmation.py b/payments/templates/pages/gocardless_confirmation.py
index 3fe7d99b..02420641 100644
--- a/payments/templates/pages/gocardless_confirmation.py
+++ b/payments/templates/pages/gocardless_confirmation.py
@@ -33,7 +33,6 @@ def get_context(context):
@frappe.whitelist(allow_guest=True)
def confirm_payment(redirect_flow_id, reference_doctype, reference_docname):
-
client = gocardless_initialization(reference_docname)
try:
@@ -59,7 +58,7 @@ def confirm_payment(redirect_flow_id, reference_doctype, reference_docname):
try:
create_mandate(data)
- except Exception as e:
+ except Exception:
frappe.log_error("GoCardless Mandate Registration Error")
gateway_controller = get_gateway_controller(reference_docname)
@@ -67,7 +66,7 @@ def confirm_payment(redirect_flow_id, reference_doctype, reference_docname):
return {"redirect_to": confirmation_url}
- except Exception as e:
+ except Exception:
frappe.log_error("GoCardless Payment Error")
return {"redirect_to": "payment-failed"}
diff --git a/payments/templates/pages/payment_success.py b/payments/templates/pages/payment_success.py
index 8985850a..e2d1115b 100644
--- a/payments/templates/pages/payment_success.py
+++ b/payments/templates/pages/payment_success.py
@@ -7,7 +7,6 @@
def get_context(context):
- token = frappe.local.form_dict.token
doc = frappe.get_doc(frappe.local.form_dict.doctype, frappe.local.form_dict.docname)
context.payment_message = ""
diff --git a/payments/templates/pages/razorpay_checkout.py b/payments/templates/pages/razorpay_checkout.py
index d0e77f6d..dab9a7ab 100644
--- a/payments/templates/pages/razorpay_checkout.py
+++ b/payments/templates/pages/razorpay_checkout.py
@@ -38,7 +38,7 @@ def get_context(context):
payment_details["subscription_id"] if payment_details.get("subscription_id") else ""
)
- except Exception as e:
+ except Exception:
frappe.redirect_to_message(
_("Invalid Token"),
_("Seems token you are using is invalid!"),
diff --git a/payments/templates/pages/stripe_checkout.py b/payments/templates/pages/stripe_checkout.py
index 7572002e..8d8c1430 100644
--- a/payments/templates/pages/stripe_checkout.py
+++ b/payments/templates/pages/stripe_checkout.py
@@ -72,9 +72,7 @@ def get_header_image(doc, gateway_controller):
@frappe.whitelist(allow_guest=True)
-def make_payment(
- stripe_token_id, data, reference_doctype=None, reference_docname=None, payment_gateway=None
-):
+def make_payment(stripe_token_id, data, reference_doctype=None, reference_docname=None, payment_gateway=None):
data = json.loads(data)
data.update({"stripe_token_id": stripe_token_id})
diff --git a/payments/utils/__init__.py b/payments/utils/__init__.py
index fb540bd5..1a494cb7 100644
--- a/payments/utils/__init__.py
+++ b/payments/utils/__init__.py
@@ -2,7 +2,7 @@
before_install,
create_payment_gateway,
delete_custom_fields,
+ erpnext_app_import_guard,
get_payment_gateway_controller,
make_custom_fields,
- erpnext_app_import_guard,
)
diff --git a/payments/utils/utils.py b/payments/utils/utils.py
index e56a89c2..fed9ac04 100644
--- a/payments/utils/utils.py
+++ b/payments/utils/utils.py
@@ -1,7 +1,8 @@
+from contextlib import contextmanager
+
import click
import frappe
from frappe import _
-from contextlib import contextmanager
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
diff --git a/pyproject.toml b/pyproject.toml
index a102875d..1eb59a56 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,14 +20,43 @@ dependencies = [
requires = ["flit_core >=3.4,<4"]
build-backend = "flit_core.buildapi"
-[tool.black]
-line-length = 99
+[tool.ruff]
+line-length = 110
+target-version = "py310"
-[tool.isort]
-line_length = 99
-multi_line_output = 3
-include_trailing_comma = true
-force_grid_wrap = 0
-use_parentheses = true
-ensure_newline_before_comments = true
-indent = "\t"
+[tool.ruff.lint]
+select = [
+ "F",
+ "E",
+ "W",
+ "I",
+ "UP",
+ "B",
+ "RUF",
+]
+ignore = [
+ "B017", # assertRaises(Exception) - should be more specific
+ "B018", # useless expression, not assigned to anything
+ "B023", # function doesn't bind loop variable - will have last iteration's value
+ "B904", # raise inside except without from
+ "E101", # indentation contains mixed spaces and tabs
+ "E402", # module level import not at top of file
+ "E501", # line too long
+ "E741", # ambiguous variable name
+ "F401", # "unused" imports
+ "F403", # can't detect undefined names from * import
+ "F405", # can't detect undefined names from * import
+ "F722", # syntax error in forward type annotation
+ "W191", # indentation contains tabs
+ "RUF001", # string contains ambiguous unicode character
+]
+typing-modules = ["frappe.types.DF"]
+
+[tool.ruff.format]
+quote-style = "double"
+indent-style = "tab"
+docstring-code-format = true
+
+[project.urls]
+Repository = "https://github.com/frappe/payments.git"
+"Bug Reports" = "https://github.com/frappe/payments/issues"