diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py
index aece5f543b..eb0b373acd 100644
--- a/.github/helper/documentation.py
+++ b/.github/helper/documentation.py
@@ -30,7 +30,7 @@ def docs_link_exists(body):
if __name__ == "__main__":
pr = sys.argv[1]
- response = requests.get("https://api.github.com/repos/frappe/frappe/pulls/{}".format(pr))
+ response = requests.get(f"https://api.github.com/repos/frappe/frappe/pulls/{pr}")
if response.ok:
payload = response.json()
diff --git a/.github/helper/install.sh b/.github/helper/install.sh
index 21d4a7b972..1a2c62c973 100644
--- a/.github/helper/install.sh
+++ b/.github/helper/install.sh
@@ -5,55 +5,63 @@ cd ~ || exit
echo "Setting Up Bench..."
pip install frappe-bench
-
bench -v init frappe-bench --skip-assets --python "$(which python)" --frappe-path "${GITHUB_WORKSPACE}"
+cd ./frappe-bench || exit
+
+bench -v setup requirements --dev
+if [ "$TYPE" == "ui" ]; then
+ bench -v setup requirements --node;
+fi
+
+echo "Setting Up Sites & Database..."
mkdir ~/frappe-bench/sites/test_site
cp "${GITHUB_WORKSPACE}/.github/helper/consumer_db/$DB.json" ~/frappe-bench/sites/test_site/site_config.json
if [ "$TYPE" == "server" ]; then
- mkdir ~/frappe-bench/sites/test_site_producer;
- cp "${GITHUB_WORKSPACE}/.github/helper/producer_db/$DB.json" ~/frappe-bench/sites/test_site_producer/site_config.json;
+ mkdir ~/frappe-bench/sites/test_site_producer;
+ cp "${GITHUB_WORKSPACE}/.github/helper/producer_db/$DB.json" ~/frappe-bench/sites/test_site_producer/site_config.json;
fi
-
if [ "$DB" == "mariadb" ];then
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL character_set_server = 'utf8mb4'";
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL character_set_server = 'utf8mb4'";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'";
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_consumer";
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_consumer'@'localhost' IDENTIFIED BY 'test_frappe_consumer'";
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_consumer\`.* TO 'test_frappe_consumer'@'localhost'";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_consumer";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_consumer'@'localhost' IDENTIFIED BY 'test_frappe_consumer'";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_consumer\`.* TO 'test_frappe_consumer'@'localhost'";
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_producer";
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_producer'@'localhost' IDENTIFIED BY 'test_frappe_producer'";
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_producer\`.* TO 'test_frappe_producer'@'localhost'";
-
- mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "FLUSH PRIVILEGES";
- fi
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_producer";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_producer'@'localhost' IDENTIFIED BY 'test_frappe_producer'";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_producer\`.* TO 'test_frappe_producer'@'localhost'";
+ mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "FLUSH PRIVILEGES";
+fi
if [ "$DB" == "postgres" ];then
- echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_consumer" -U postgres;
- echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_consumer WITH PASSWORD 'test_frappe'" -U postgres;
+ echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_consumer" -U postgres;
+ echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_consumer WITH PASSWORD 'test_frappe'" -U postgres;
- echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_producer" -U postgres;
- echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_producer WITH PASSWORD 'test_frappe'" -U postgres;
+ echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_producer" -U postgres;
+ echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_producer WITH PASSWORD 'test_frappe'" -U postgres;
fi
-cd ./frappe-bench || exit
+echo "Setting Up Procfile..."
sed -i 's/^watch:/# watch:/g' Procfile
sed -i 's/^schedule:/# schedule:/g' Procfile
+if [ "$TYPE" == "server" ]; then
+ sed -i 's/^socketio:/# socketio:/g' Procfile;
+ sed -i 's/^redis_socketio:/# redis_socketio:/g' Procfile;
+fi
+if [ "$TYPE" == "ui" ]; then
+ sed -i 's/^web: bench serve/web: bench serve --with-coverage/g' Procfile;
+fi
-if [ "$TYPE" == "server" ]; then sed -i 's/^socketio:/# socketio:/g' Procfile; fi
-if [ "$TYPE" == "server" ]; then sed -i 's/^redis_socketio:/# redis_socketio:/g' Procfile; fi
-
-if [ "$TYPE" == "ui" ]; then bench -v setup requirements --node; fi
-bench -v setup requirements --dev
-
-if [ "$TYPE" == "ui" ]; then sed -i 's/^web: bench serve/web: bench serve --with-coverage/g' Procfile; fi
+echo "Starting Bench..."
bench start &> bench_start.log &
bench --site test_site reinstall --yes
-if [ "$TYPE" == "server" ]; then bench --site test_site_producer reinstall --yes; fi
-if [ "$TYPE" == "server" ]; then CI=Yes bench build --app frappe; fi
+if [ "$TYPE" == "server" ]; then
+ bench --site test_site_producer reinstall --yes;
+ CI=Yes bench build --app frappe;
+fi
diff --git a/.github/helper/install_dependencies.sh b/.github/helper/install_dependencies.sh
index f16bd61a53..694b0a9504 100644
--- a/.github/helper/install_dependencies.sh
+++ b/.github/helper/install_dependencies.sh
@@ -3,8 +3,11 @@ set -e
echo "Setting Up System Dependencies..."
-wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
-sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb
+install_wkhtmltopdf() {
+ wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
+ sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb
+}
+install_wkhtmltopdf &
curl -LsS -O https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
sudo bash mariadb_repo_setup --mariadb-server-version=10.6
diff --git a/.github/helper/translation.py b/.github/helper/translation.py
index 9146b3b32b..72f661d3e1 100644
--- a/.github/helper/translation.py
+++ b/.github/helper/translation.py
@@ -20,19 +20,12 @@ for _file in files_to_scan:
if 'frappe-lint: disable-translate' in line:
continue
- start_matches = start_pattern.search(line)
- if start_matches:
- starts_with_f = starts_with_f_pattern.search(line)
-
- if starts_with_f:
- has_f_string = f_string_pattern.search(line)
- if has_f_string:
+ if start_matches := start_pattern.search(line):
+ if starts_with_f := starts_with_f_pattern.search(line):
+ if has_f_string := f_string_pattern.search(line):
errors_encounter += 1
print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}')
- continue
- else:
- continue
-
+ continue
match = pattern.search(line)
error_found = False
diff --git a/.github/workflows/release.yml b/.github/workflows/create-release.yml
similarity index 100%
rename from .github/workflows/release.yml
rename to .github/workflows/create-release.yml
diff --git a/.github/workflows/deps-checker.yml b/.github/workflows/deps-checker.yml
deleted file mode 100644
index d3fa8c80fb..0000000000
--- a/.github/workflows/deps-checker.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-name: 'Python Dependency Check'
-on:
- pull_request:
- workflow_dispatch:
- push:
- branches: [ develop ]
-
-permissions:
- contents: read
-
-jobs:
- deps-vulnerable-check:
- name: 'Vulnerable Dependency'
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/setup-python@v4
- with:
- python-version: '3.10'
- - uses: actions/checkout@v3
- - run: pip install pip-audit
- - run: pip-audit ${GITHUB_WORKSPACE}
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
deleted file mode 100644
index 988c2dcc6c..0000000000
--- a/.github/workflows/docker-release.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: 'Trigger Docker build on release'
-on:
- release:
- types: [released]
-permissions:
- contents: read
-
-jobs:
- curl:
- permissions:
- contents: none
- name: 'Trigger Docker build on release'
- runs-on: ubuntu-latest
- container:
- image: alpine:latest
- steps:
- - name: curl
- run: |
- apk add curl bash
- curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}'
diff --git a/.github/workflows/docs-checker.yml b/.github/workflows/docs-checker.yml
deleted file mode 100644
index e61ee6355a..0000000000
--- a/.github/workflows/docs-checker.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: 'Documentation Check'
-on:
- pull_request:
- types: [ opened, synchronize, reopened, edited ]
-
-permissions:
- contents: read
-
-jobs:
- docs-required:
- name: 'Documentation Required'
- runs-on: ubuntu-latest
-
- steps:
- - name: 'Setup Environment'
- uses: actions/setup-python@v4
- with:
- python-version: '3.10'
-
- - name: 'Clone repo'
- uses: actions/checkout@v3
-
- - name: Validate Docs
- env:
- PR_NUMBER: ${{ github.event.number }}
- run: |
- pip install requests --quiet
- python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER
diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml
index 6d1029d51d..f56c108f6b 100644
--- a/.github/workflows/linters.yml
+++ b/.github/workflows/linters.yml
@@ -1,29 +1,86 @@
name: Linters
on:
- pull_request: { }
+ pull_request:
+ workflow_dispatch:
+ push:
+ branches: [ develop ]
+
+permissions:
+ contents: read
+
+concurrency:
+ group: commitcheck-frappe-${{ github.event.number }}
+ cancel-in-progress: true
jobs:
-
- linters:
- name: Frappe Linter
+ commit-lint:
+ name: 'Semantic Commits'
runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request'
+
steps:
- uses: actions/checkout@v3
+ with:
+ fetch-depth: 200
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 16
+ check-latest: true
- - name: Set up Python
+ - name: Check commit titles
+ run: |
+ npm install @commitlint/cli @commitlint/config-conventional
+ npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }}
+
+ docs-required:
+ name: 'Documentation Required'
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request'
+
+ steps:
+ - name: 'Setup Environment'
uses: actions/setup-python@v4
with:
python-version: '3.10'
+ - uses: actions/checkout@v3
- - name: Install and Run Pre-commit
- uses: pre-commit/action@v3.0.0
+ - name: Validate Docs
+ env:
+ PR_NUMBER: ${{ github.event.number }}
+ run: |
+ pip install requests --quiet
+ python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER
+
+ linter:
+ name: 'Frappe Linter'
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request'
+
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+ - uses: pre-commit/action@v3.0.0
- name: Download Semgrep rules
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
- - name: Download semgrep
- run: pip install semgrep==0.97.0
-
- name: Run Semgrep rules
- run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness
+ run: |
+ pip install semgrep==0.97.0
+ semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness
+
+ deps-vulnerable-check:
+ name: 'Vulnerable Dependency Check'
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+ - uses: actions/checkout@v3
+ - run: |
+ pip install pip-audit
+ pip-audit ${GITHUB_WORKSPACE}
diff --git a/.github/workflows/publish-assets-releases.yml b/.github/workflows/on_release.yml
similarity index 71%
rename from .github/workflows/publish-assets-releases.yml
rename to .github/workflows/on_release.yml
index ff1656e55d..59e14a8c4d 100644
--- a/.github/workflows/publish-assets-releases.yml
+++ b/.github/workflows/on_release.yml
@@ -1,8 +1,11 @@
-name: 'Frappe Assets'
+name: 'Release'
on:
release:
- types: [ created ]
+ types: [released]
+
+permissions:
+ contents: read
env:
GITHUB_TOKEN: ${{ github.token }}
@@ -47,3 +50,16 @@ jobs:
asset_path: build/assets.tar.gz
asset_name: assets.tar.gz
asset_content_type: application/octet-stream
+
+ docker-release:
+ name: 'Trigger Docker build on release'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: none
+ container:
+ image: alpine:latest
+ steps:
+ - name: curl
+ run: |
+ apk add curl bash
+ curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}'
diff --git a/.github/workflows/patch-mariadb-tests.yml b/.github/workflows/patch-mariadb-tests.yml
index e18cbf53ba..3412fe7503 100644
--- a/.github/workflows/patch-mariadb-tests.yml
+++ b/.github/workflows/patch-mariadb-tests.yml
@@ -1,7 +1,8 @@
-name: Patch
-
-on: [pull_request, workflow_dispatch]
+name: Server (MariaDB)
+on:
+ pull_request:
+ workflow_dispatch:
concurrency:
group: patch-mariadb-develop-${{ github.event.number }}
@@ -12,11 +13,10 @@ permissions:
jobs:
test:
+ name: Patch
runs-on: ubuntu-latest
timeout-minutes: 60
- name: Patch Test
-
services:
mariadb:
image: mariadb:10.6
diff --git a/.github/workflows/publish-assets-develop.yml b/.github/workflows/publish-assets-develop.yml
index 467922e766..12bf9eca55 100644
--- a/.github/workflows/publish-assets-develop.yml
+++ b/.github/workflows/publish-assets-develop.yml
@@ -1,6 +1,7 @@
name: 'Frappe Assets'
on:
+ workflow_dispatch:
push:
branches: [ develop ]
diff --git a/.github/workflows/semantic-commits.yml b/.github/workflows/semantic-commits.yml
deleted file mode 100644
index 7afa02d1b9..0000000000
--- a/.github/workflows/semantic-commits.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: Semantic Commits
-
-on:
- pull_request: {}
-
-permissions:
- contents: read
-
-concurrency:
- group: commitcheck-frappe-${{ github.event.number }}
- cancel-in-progress: true
-
-jobs:
- commitlint:
- name: Check Commit Titles
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- with:
- fetch-depth: 200
-
- - uses: actions/setup-node@v3
- with:
- node-version: 16
- check-latest: true
-
- - name: Check commit titles
- run: |
- npm install @commitlint/cli @commitlint/config-conventional
- npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }}
diff --git a/.github/workflows/server-mariadb-tests.yml b/.github/workflows/server-mariadb-tests.yml
index 9e7cffba5d..c8ccfa7862 100644
--- a/.github/workflows/server-mariadb-tests.yml
+++ b/.github/workflows/server-mariadb-tests.yml
@@ -1,4 +1,4 @@
-name: Server
+name: Server (MariaDB)
on:
pull_request:
@@ -16,6 +16,7 @@ permissions:
jobs:
test:
+ name: Unit Tests
runs-on: ubuntu-latest
timeout-minutes: 60
@@ -24,8 +25,6 @@ jobs:
matrix:
container: [1, 2]
- name: Python Unit Tests (MariaDB)
-
services:
mariadb:
image: mariadb:10.6
diff --git a/.github/workflows/server-postgres-tests.yml b/.github/workflows/server-postgres-tests.yml
index 1741752e6b..9760067197 100644
--- a/.github/workflows/server-postgres-tests.yml
+++ b/.github/workflows/server-postgres-tests.yml
@@ -1,4 +1,4 @@
-name: Server
+name: Server (Postgres)
on:
pull_request:
@@ -15,6 +15,7 @@ permissions:
jobs:
test:
+ name: Unit Tests
runs-on: ubuntu-latest
timeout-minutes: 60
@@ -23,8 +24,6 @@ jobs:
matrix:
container: [1, 2]
- name: Python Unit Tests (Postgres)
-
services:
postgres:
image: postgres:12.4
diff --git a/esbuild/utils.js b/esbuild/utils.js
index 82490adb36..b2a4e98d54 100644
--- a/esbuild/utils.js
+++ b/esbuild/utils.js
@@ -112,16 +112,21 @@ function log(...args) {
function get_redis_subscriber(kind) {
// get redis subscriber that aborts after 10 connection attempts
- let { get_redis_subscriber: get_redis } = require("../node_utils");
- return get_redis(kind, {
- retry_strategy: function(options) {
+ let retry_strategy;
+ let { get_redis_subscriber: get_redis, get_conf } = require("../node_utils");
+
+ if (process.env.CI == 1 || get_conf().developer_mode == 1) {
+ retry_strategy = () => { }
+ } else {
+ retry_strategy = function (options) {
// abort after 10 connection attempts
if (options.attempt > 10) {
return undefined;
}
return Math.min(options.attempt * 100, 2000);
}
- });
+ }
+ return get_redis(kind, { retry_strategy });
}
module.exports = {
diff --git a/frappe/boot.py b/frappe/boot.py
index e43446f352..ab559d7c4d 100644
--- a/frappe/boot.py
+++ b/frappe/boot.py
@@ -391,7 +391,6 @@ def get_notification_settings():
return frappe.get_cached_doc("Notification Settings", frappe.session.user)
-@frappe.whitelist()
def get_link_title_doctypes():
dts = frappe.get_all("DocType", {"show_title_field_in_link": 1})
custom_dts = frappe.get_all(
diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py
index 7a66d45c73..e1faf331d6 100755
--- a/frappe/core/doctype/file/file.py
+++ b/frappe/core/doctype/file/file.py
@@ -262,7 +262,7 @@ class File(Document):
def validate_remote_file(self):
"""Validates if file uploaded using URL already exist"""
site_url = get_url()
- if "/files/" in self.file_url and self.file_url.startswith(site_url):
+ if self.file_url and "/files/" in self.file_url and self.file_url.startswith(site_url):
self.file_url = self.file_url.split(site_url, 1)[1]
def set_folder_name(self):
diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py
index a9d40b35b1..d849a2de4d 100644
--- a/frappe/core/doctype/file/test_file.py
+++ b/frappe/core/doctype/file/test_file.py
@@ -510,6 +510,16 @@ class TestFile(FrappeTestCase):
).insert(ignore_permissions=True)
self.assertRaisesRegex(ValidationError, "not a zip file", test_file.unzip)
+ def test_create_file_without_file_url(self):
+ test_file = frappe.get_doc(
+ {
+ "doctype": "File",
+ "file_name": "logo",
+ "content": "frappe",
+ }
+ ).insert()
+ assert test_file is not None
+
class TestAttachment(unittest.TestCase):
test_doctype = "Test For Attachment"
diff --git a/frappe/core/doctype/payment_gateway/__init__.py b/frappe/core/doctype/payment_gateway/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/core/doctype/payment_gateway/payment_gateway.js b/frappe/core/doctype/payment_gateway/payment_gateway.js
deleted file mode 100644
index 0eff5a5608..0000000000
--- a/frappe/core/doctype/payment_gateway/payment_gateway.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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) {
-
- }
-});
diff --git a/frappe/core/doctype/payment_gateway/payment_gateway.json b/frappe/core/doctype/payment_gateway/payment_gateway.json
deleted file mode 100644
index 7195b3949e..0000000000
--- a/frappe/core/doctype/payment_gateway/payment_gateway.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "actions": [],
- "autoname": "field:gateway",
- "creation": "2022-01-24 21:09:47.229371",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "gateway",
- "gateway_settings",
- "gateway_controller"
- ],
- "fields": [
- {
- "fieldname": "gateway",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Gateway",
- "reqd": 1,
- "unique": 1
- },
- {
- "fieldname": "gateway_settings",
- "fieldtype": "Link",
- "label": "Gateway Settings",
- "options": "DocType"
- },
- {
- "fieldname": "gateway_controller",
- "fieldtype": "Dynamic Link",
- "label": "Gateway Controller",
- "options": "gateway_settings"
- }
- ],
- "links": [],
- "modified": "2022-01-24 21:17:03.864719",
- "modified_by": "Administrator",
- "module": "Core",
- "name": "Payment Gateway",
- "naming_rule": "By fieldname",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "read": 1,
- "role": "System Manager",
- "write": 1
- }
- ],
- "quick_entry": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "states": []
-}
\ No newline at end of file
diff --git a/frappe/core/doctype/payment_gateway/payment_gateway.py b/frappe/core/doctype/payment_gateway/payment_gateway.py
deleted file mode 100644
index 74306ae4ad..0000000000
--- a/frappe/core/doctype/payment_gateway/payment_gateway.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
-# License: MIT. See LICENSE
-
-from frappe.model.document import Document
-
-
-class PaymentGateway(Document):
- pass
diff --git a/frappe/core/doctype/payment_gateway/test_payment_gateway.py b/frappe/core/doctype/payment_gateway/test_payment_gateway.py
deleted file mode 100644
index 6900e79434..0000000000
--- a/frappe/core/doctype/payment_gateway/test_payment_gateway.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-import unittest
-
-# test_records = frappe.get_test_records('Payment Gateway')
-
-
-class TestPaymentGateway(unittest.TestCase):
- pass
diff --git a/frappe/core/web_form/edit_profile/edit_profile.json b/frappe/core/web_form/edit_profile/edit_profile.json
index cedef71c0e..8abb2164f9 100644
--- a/frappe/core/web_form/edit_profile/edit_profile.json
+++ b/frappe/core/web_form/edit_profile/edit_profile.json
@@ -1,13 +1,10 @@
{
- "accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 1,
"allow_incomplete": 0,
"allow_multiple": 0,
"allow_print": 0,
- "amount": 0.0,
- "amount_based_on_field": 0,
"apply_document_permissions": 0,
"breadcrumbs": "[{\"title\": _(\"My Account\"), \"route\": \"me\"}]",
"creation": "2016-09-19 05:16:59.242754",
diff --git a/frappe/database/database.py b/frappe/database/database.py
index 68286507ba..c55704eb64 100644
--- a/frappe/database/database.py
+++ b/frappe/database/database.py
@@ -54,6 +54,23 @@ class Database:
CHILD_TABLE_COLUMNS = ("parent", "parenttype", "parentfield")
MAX_WRITES_PER_TRANSACTION = 200_000
+ # NOTE:
+ # FOR MARIADB - using no cache - as during backup, if the sequence was used in anyform,
+ # it drops the cache and uses the next non cached value in setval query and
+ # puts that in the backup file, which will start the counter
+ # from that value when inserting any new record in the doctype.
+ # By default the cache is 1000 which will mess up the sequence when
+ # using the system after a restore.
+ #
+ # Another case could be if the cached values expire then also there is a chance of
+ # the cache being skipped.
+ #
+ # FOR POSTGRES - The sequence cache for postgres is per connection.
+ # Since we're opening and closing connections for every request this results in skipping the cache
+ # to the next non-cached value hence not using cache in postgres.
+ # ref: https://stackoverflow.com/questions/21356375/postgres-9-0-4-sequence-skipping-numbers
+ SEQUENCE_CACHE = 0
+
class InvalidColumnName(frappe.ValidationError):
pass
diff --git a/frappe/database/mariadb/database.py b/frappe/database/mariadb/database.py
index 5e6d62f842..303098049a 100644
--- a/frappe/database/mariadb/database.py
+++ b/frappe/database/mariadb/database.py
@@ -129,15 +129,6 @@ class MariaDBConnectionUtil:
class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database):
REGEX_CHARACTER = "regexp"
-
- # NOTE: using a very small cache - as during backup, if the sequence was used in anyform,
- # it drops the cache and uses the next non cached value in setval query and
- # puts that in the backup file, which will start the counter
- # from that value when inserting any new record in the doctype.
- # By default the cache is 1000 which will mess up the sequence when
- # using the system after a restore.
- # issue link: https://jira.mariadb.org/browse/MDEV-21786
- SEQUENCE_CACHE = 50
CONVERSION_MAP = conversions | {
FIELD_TYPE.NEWDECIMAL: float,
FIELD_TYPE.DATETIME: get_datetime,
diff --git a/frappe/database/mariadb/schema.py b/frappe/database/mariadb/schema.py
index 24a78012e1..99297fbab2 100644
--- a/frappe/database/mariadb/schema.py
+++ b/frappe/database/mariadb/schema.py
@@ -44,7 +44,7 @@ class MariaDBTable(DBTable):
# NOTE: not used nextval func as default as the ability to restore
# database with sequences has bugs in mariadb and gives a scary error.
- # issue link: https://jira.mariadb.org/browse/MDEV-21786
+ # issue link: https://jira.mariadb.org/browse/MDEV-20070
name_column = "name bigint primary key"
# create table
diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py
index 58b63e6547..cb566736ad 100644
--- a/frappe/database/postgres/database.py
+++ b/frappe/database/postgres/database.py
@@ -102,12 +102,6 @@ class PostgresExceptionUtil:
class PostgresDatabase(PostgresExceptionUtil, Database):
REGEX_CHARACTER = "~"
-
- # NOTE; The sequence cache for postgres is per connection.
- # Since we're opening and closing connections for every transaction this results in skipping the cache
- # to the next non-cached value hence not using cache in postgres.
- # ref: https://stackoverflow.com/questions/21356375/postgres-9-0-4-sequence-skipping-numbers
- SEQUENCE_CACHE = 0
default_port = "5432"
def setup_type_map(self):
diff --git a/frappe/database/query.py b/frappe/database/query.py
index 31c5d20ae3..89e3857f9e 100644
--- a/frappe/database/query.py
+++ b/frappe/database/query.py
@@ -187,8 +187,6 @@ class Engine:
@cached_property
def OPERATOR_MAP(self):
- from frappe.boot import get_additional_filters_from_hooks
-
# default operators
all_operators = OPERATOR_MAP.copy()
diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json
index a5d30c10e5..a5aa6cc20a 100644
--- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json
+++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json
@@ -42,7 +42,8 @@
"column_break_2",
"color",
"section_break_10",
- "last_synced_on"
+ "last_synced_on",
+ "roles"
],
"fields": [
{
@@ -277,13 +278,20 @@
"fieldtype": "Link",
"label": "Parent Document Type",
"options": "DocType"
+ },
+ {
+ "fieldname": "roles",
+ "fieldtype": "Table",
+ "label": "Roles",
+ "options": "Has Role"
}
],
"links": [],
- "modified": "2021-11-09 17:18:11.456145",
+ "modified": "2022-07-27 11:09:09.203236",
"modified_by": "Administrator",
"module": "Desk",
"name": "Dashboard Chart",
+ "naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
@@ -323,5 +331,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py
index 75f230a901..aa76932050 100644
--- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py
+++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py
@@ -11,7 +11,7 @@ from frappe.config import get_modules_from_all_apps_for_user
from frappe.model.document import Document
from frappe.model.naming import append_number_if_name_exists
from frappe.modules.export_file import export_to_files
-from frappe.utils import cint, get_datetime, getdate, now_datetime, nowdate
+from frappe.utils import cint, get_datetime, getdate, has_common, now_datetime, nowdate
from frappe.utils.dashboard import cache_source
from frappe.utils.data import format_date
from frappe.utils.dateutils import (
@@ -87,6 +87,11 @@ def has_permission(doc, ptype, user):
if doc.document_type in allowed_doctypes:
return True
+ if doc.roles:
+ allowed = [d.role for d in doc.roles]
+ if has_common(roles, allowed):
+ return True
+
return False
diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py
index 17734635dd..482f404e65 100644
--- a/frappe/desk/doctype/notification_log/notification_log.py
+++ b/frappe/desk/doctype/notification_log/notification_log.py
@@ -133,6 +133,22 @@ def get_email_header(doc):
return header_map[doc.type or "Default"]
+@frappe.whitelist()
+def get_notification_logs(limit=20):
+ notification_logs = frappe.db.get_list(
+ "Notification Log", fields=["*"], limit=limit, order_by="creation desc"
+ )
+
+ users = [log.from_user for log in notification_logs]
+ users = [*set(users)] # remove duplicates
+ user_info = frappe._dict()
+
+ for user in users:
+ frappe.utils.add_user_info(user, user_info)
+
+ return {"notification_logs": notification_logs, "user_info": user_info}
+
+
@frappe.whitelist()
def mark_all_as_read():
unread_docs_list = frappe.db.get_all(
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 66820ecd0f..14e76adc22 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -199,7 +199,6 @@ scheduler_events = {
"frappe.email.queue.flush",
"frappe.email.doctype.email_account.email_account.pull",
"frappe.email.doctype.email_account.email_account.notify_unreplied",
- "frappe.integrations.doctype.razorpay_settings.razorpay_settings.capture_payment",
"frappe.utils.global_search.sync_global_search",
"frappe.monitor.flush",
],
diff --git a/frappe/integrations/doctype/braintree_settings/__init__.py b/frappe/integrations/doctype/braintree_settings/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/integrations/doctype/braintree_settings/braintree_settings.js b/frappe/integrations/doctype/braintree_settings/braintree_settings.js
deleted file mode 100644
index c844022cec..0000000000
--- a/frappe/integrations/doctype/braintree_settings/braintree_settings.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Braintree Settings', {
-
-});
diff --git a/frappe/integrations/doctype/braintree_settings/braintree_settings.json b/frappe/integrations/doctype/braintree_settings/braintree_settings.json
deleted file mode 100644
index eebf64dfd1..0000000000
--- a/frappe/integrations/doctype/braintree_settings/braintree_settings.json
+++ /dev/null
@@ -1,273 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "field:gateway_name",
- "beta": 0,
- "creation": "2018-02-05 13:46:12.101852",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "gateway_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Payment Gateway Name",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_2",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "merchant_id",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Merchant ID",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "public_key",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Public Key",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "private_key",
- "fieldtype": "Password",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Private Key",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "use_sandbox",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Use Sandbox",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "header_img",
- "fieldtype": "Attach Image",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Header Image",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-02-05 14:33:06.050377",
- "modified_by": "Administrator",
- "module": "Integrations",
- "name": "Braintree Settings",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/frappe/integrations/doctype/braintree_settings/braintree_settings.py b/frappe/integrations/doctype/braintree_settings/braintree_settings.py
deleted file mode 100644
index 35481c67c1..0000000000
--- a/frappe/integrations/doctype/braintree_settings/braintree_settings.py
+++ /dev/null
@@ -1,287 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies and contributors
-# License: MIT. See LICENSE
-
-from urllib.parse import urlencode
-
-import braintree
-
-import frappe
-from frappe import _
-from frappe.integrations.utils import create_payment_gateway, create_request_log
-from frappe.model.document import Document
-from frappe.utils import call_hook_method, get_url
-
-
-class BraintreeSettings(Document):
- supported_currencies = [
- "AED",
- "AMD",
- "AOA",
- "ARS",
- "AUD",
- "AWG",
- "AZN",
- "BAM",
- "BBD",
- "BDT",
- "BGN",
- "BIF",
- "BMD",
- "BND",
- "BOB",
- "BRL",
- "BSD",
- "BWP",
- "BYN",
- "BZD",
- "CAD",
- "CHF",
- "CLP",
- "CNY",
- "COP",
- "CRC",
- "CVE",
- "CZK",
- "DJF",
- "DKK",
- "DOP",
- "DZD",
- "EGP",
- "ETB",
- "EUR",
- "FJD",
- "FKP",
- "GBP",
- "GEL",
- "GHS",
- "GIP",
- "GMD",
- "GNF",
- "GTQ",
- "GYD",
- "HKD",
- "HNL",
- "HRK",
- "HTG",
- "HUF",
- "IDR",
- "ILS",
- "INR",
- "ISK",
- "JMD",
- "JPY",
- "KES",
- "KGS",
- "KHR",
- "KMF",
- "KRW",
- "KYD",
- "KZT",
- "LAK",
- "LBP",
- "LKR",
- "LRD",
- "LSL",
- "LTL",
- "MAD",
- "MDL",
- "MKD",
- "MNT",
- "MOP",
- "MUR",
- "MVR",
- "MWK",
- "MXN",
- "MYR",
- "MZN",
- "NAD",
- "NGN",
- "NIO",
- "NOK",
- "NPR",
- "NZD",
- "PAB",
- "PEN",
- "PGK",
- "PHP",
- "PKR",
- "PLN",
- "PYG",
- "QAR",
- "RON",
- "RSD",
- "RUB",
- "RWF",
- "SAR",
- "SBD",
- "SCR",
- "SEK",
- "SGD",
- "SHP",
- "SLL",
- "SOS",
- "SRD",
- "STD",
- "SVC",
- "SYP",
- "SZL",
- "THB",
- "TJS",
- "TOP",
- "TRY",
- "TTD",
- "TWD",
- "TZS",
- "UAH",
- "UGX",
- "USD",
- "UYU",
- "UZS",
- "VEF",
- "VND",
- "VUV",
- "WST",
- "XAF",
- "XCD",
- "XOF",
- "XPF",
- "YER",
- "ZAR",
- "ZMK",
- "ZWD",
- ]
-
- def validate(self):
- if not self.flags.ignore_mandatory:
- self.configure_braintree()
-
- def on_update(self):
- create_payment_gateway(
- "Braintree-" + self.gateway_name, settings="Braintree Settings", controller=self.gateway_name
- )
- call_hook_method("payment_gateway_enabled", gateway="Braintree-" + self.gateway_name)
-
- def configure_braintree(self):
- if self.use_sandbox:
- environment = "sandbox"
- else:
- environment = "production"
-
- braintree.Configuration.configure(
- environment=environment,
- merchant_id=self.merchant_id,
- public_key=self.public_key,
- private_key=self.get_password(fieldname="private_key", raise_exception=False),
- )
-
- def validate_transaction_currency(self, currency):
- if currency not in self.supported_currencies:
- frappe.throw(
- _(
- "Please select another payment method. Stripe does not support transactions in currency '{0}'"
- ).format(currency)
- )
-
- def get_payment_url(self, **kwargs):
- return get_url(f"./integrations/braintree_checkout?{urlencode(kwargs)}")
-
- def create_payment_request(self, data):
- self.data = frappe._dict(data)
-
- try:
- self.integration_request = create_request_log(self.data, service_name="Braintree")
- return self.create_charge_on_braintree()
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
- return {
- "redirect_to": frappe.redirect_to_message(
- _("Server Error"),
- _(
- "There seems to be an issue with the server's braintree configuration. Don't worry, in case of failure, the amount will get refunded to your account."
- ),
- ),
- "status": 401,
- }
-
- def create_charge_on_braintree(self):
- self.configure_braintree()
-
- redirect_to = self.data.get("redirect_to") or None
- redirect_message = self.data.get("redirect_message") or None
-
- result = braintree.Transaction.sale(
- {
- "amount": self.data.amount,
- "payment_method_nonce": self.data.payload_nonce,
- "options": {"submit_for_settlement": True},
- }
- )
-
- if result.is_success:
- self.integration_request.db_set("status", "Completed", update_modified=False)
- self.flags.status_changed_to = "Completed"
- self.integration_request.db_set("output", result.transaction.status, update_modified=False)
-
- elif result.transaction:
- self.integration_request.db_set("status", "Failed", update_modified=False)
- error_log = frappe.log_error(
- "code: "
- + str(result.transaction.processor_response_code)
- + " | text: "
- + str(result.transaction.processor_response_text),
- "Braintree Payment Error",
- )
- self.integration_request.db_set("error", error_log.error, update_modified=False)
- else:
- self.integration_request.db_set("status", "Failed", update_modified=False)
- for error in result.errors.deep_errors:
- error_log = frappe.log_error(
- "code: " + str(error.code) + " | message: " + str(error.message), "Braintree Payment Error"
- )
- self.integration_request.db_set("error", error_log.error, update_modified=False)
-
- if self.flags.status_changed_to == "Completed":
- status = "Completed"
- if self.data.reference_doctype and self.data.reference_docname:
- custom_redirect_to = None
- try:
- custom_redirect_to = frappe.get_doc(
- self.data.reference_doctype, self.data.reference_docname
- ).run_method("on_payment_authorized", self.flags.status_changed_to)
- braintree_success_page = frappe.get_hooks("braintree_success_page")
- if braintree_success_page:
- custom_redirect_to = frappe.get_attr(braintree_success_page[-1])(self.data)
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
- if custom_redirect_to:
- redirect_to = custom_redirect_to
-
- redirect_url = "payment-success"
- else:
- status = "Error"
- redirect_url = "payment-failed"
-
- if redirect_to:
- redirect_url += "?" + urlencode({"redirect_to": redirect_to})
- if redirect_message:
- redirect_url += "&" + urlencode({"redirect_message": redirect_message})
-
- return {"redirect_to": redirect_url, "status": status}
-
-
-def get_gateway_controller(doc):
- payment_request = frappe.get_doc("Payment Request", doc)
- gateway_controller = frappe.db.get_value(
- "Payment Gateway", payment_request.payment_gateway, "gateway_controller"
- )
- return gateway_controller
-
-
-def get_client_token(doc):
- gateway_controller = get_gateway_controller(doc)
- settings = frappe.get_doc("Braintree Settings", gateway_controller)
- settings.configure_braintree()
-
- return braintree.ClientToken.generate()
diff --git a/frappe/integrations/doctype/braintree_settings/test_braintree_settings.py b/frappe/integrations/doctype/braintree_settings/test_braintree_settings.py
deleted file mode 100644
index 38d8909dfd..0000000000
--- a/frappe/integrations/doctype/braintree_settings/test_braintree_settings.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies and Contributors
-# License: MIT. See LICENSE
-import unittest
-
-
-class TestBraintreeSettings(unittest.TestCase):
- pass
diff --git a/frappe/integrations/doctype/paypal_settings/__init__.py b/frappe/integrations/doctype/paypal_settings/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/integrations/doctype/paypal_settings/paypal_settings.js b/frappe/integrations/doctype/paypal_settings/paypal_settings.js
deleted file mode 100644
index 63480bc927..0000000000
--- a/frappe/integrations/doctype/paypal_settings/paypal_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('PayPal Settings', {
- refresh: function(frm) {
-
- }
-});
diff --git a/frappe/integrations/doctype/paypal_settings/paypal_settings.json b/frappe/integrations/doctype/paypal_settings/paypal_settings.json
deleted file mode 100644
index 8d48496a4c..0000000000
--- a/frappe/integrations/doctype/paypal_settings/paypal_settings.json
+++ /dev/null
@@ -1,202 +0,0 @@
-{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-09-21 08:03:01.009852",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "System",
- "editable_grid": 1,
- "fields": [
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "api_username",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "API Username",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "api_password",
- "fieldtype": "Password",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "API Password",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "signature",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Signature",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Check this if you are testing your payment using the Sandbox API",
- "fieldname": "paypal_sandbox",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Use Sandbox",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Mention transaction completion page URL",
- "fieldname": "redirect_to",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Redirect To",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 1,
-
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-12-29 14:40:31.574789",
- "modified_by": "Administrator",
- "module": "Integrations",
- "name": "PayPal Settings",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 1,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/frappe/integrations/doctype/paypal_settings/paypal_settings.py b/frappe/integrations/doctype/paypal_settings/paypal_settings.py
deleted file mode 100644
index 99c499200b..0000000000
--- a/frappe/integrations/doctype/paypal_settings/paypal_settings.py
+++ /dev/null
@@ -1,505 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies and contributors
-# License: MIT. See LICENSE
-
-"""
-# Integrating PayPal
-
-### 1. Validate Currency Support
-
-Example:
-
- from frappe.integrations.utils import get_payment_gateway_controller
-
- controller = get_payment_gateway_controller("PayPal")
- controller().validate_transaction_currency(currency)
-
-### 2. Redirect for payment
-
-Example:
-
- payment_details = {
- "amount": 600,
- "title": "Payment for bill : 111",
- "description": "payment via cart",
- "reference_doctype": "Payment Request",
- "reference_docname": "PR0001",
- "payer_email": "NuranVerkleij@example.com",
- "payer_name": "Nuran Verkleij",
- "order_id": "111",
- "currency": "USD",
- "payment_gateway": "Razorpay",
- "subscription_details": {
- "plan_id": "plan_12313", # if Required
- "start_date": "2018-08-30",
- "billing_period": "Month" #(Day, Week, SemiMonth, Month, Year),
- "billing_frequency": 1,
- "customer_notify": 1,
- "upfront_amount": 1000
- }
- }
-
- # redirect the user to this url
- url = controller().get_payment_url(**payment_details)
-
-
-### 3. On Completion of Payment
-
-Write a method for `on_payment_authorized` in the reference doctype
-
-Example:
-
- def on_payment_authorized(payment_status):
- # your code to handle callback
-
-##### Note:
-
-payment_status - payment gateway will put payment status on callback.
-For paypal payment status parameter is one from: [Completed, Cancelled, Failed]
-
-
-More Details:
-
-
-"""
-
-import json
-from urllib.parse import urlencode
-
-import pytz
-
-import frappe
-from frappe import _
-from frappe.integrations.utils import create_payment_gateway, create_request_log, make_post_request
-from frappe.model.document import Document
-from frappe.utils import call_hook_method, cint, get_datetime, get_url
-
-api_path = "/api/method/frappe.integrations.doctype.paypal_settings.paypal_settings"
-
-
-class PayPalSettings(Document):
- supported_currencies = [
- "AUD",
- "BRL",
- "CAD",
- "CZK",
- "DKK",
- "EUR",
- "HKD",
- "HUF",
- "ILS",
- "JPY",
- "MYR",
- "MXN",
- "TWD",
- "NZD",
- "NOK",
- "PHP",
- "PLN",
- "GBP",
- "RUB",
- "SGD",
- "SEK",
- "CHF",
- "THB",
- "TRY",
- "USD",
- ]
-
- def __setup__(self):
- setattr(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)
-
- def validate(self):
- create_payment_gateway("PayPal")
- call_hook_method("payment_gateway_enabled", gateway="PayPal")
- if not self.flags.ignore_mandatory:
- self.validate_paypal_credentails()
-
- def on_update(self):
- pass
-
- def validate_transaction_currency(self, currency):
- if currency not in self.supported_currencies:
- frappe.throw(
- _(
- "Please select another payment method. PayPal does not support transactions in currency '{0}'"
- ).format(currency)
- )
-
- def get_paypal_params_and_url(self):
- params = {
- "USER": self.api_username,
- "PWD": self.get_password(fieldname="api_password", raise_exception=False),
- "SIGNATURE": self.signature,
- "VERSION": "98",
- "METHOD": "GetPalDetails",
- }
-
- if hasattr(self, "use_sandbox") and self.use_sandbox:
- params.update(
- {
- "USER": frappe.conf.sandbox_api_username,
- "PWD": frappe.conf.sandbox_api_password,
- "SIGNATURE": frappe.conf.sandbox_signature,
- }
- )
-
- api_url = (
- "https://api-3t.sandbox.paypal.com/nvp"
- if (self.paypal_sandbox or self.use_sandbox)
- else "https://api-3t.paypal.com/nvp"
- )
-
- return params, api_url
-
- def validate_paypal_credentails(self):
- params, url = self.get_paypal_params_and_url()
- params = urlencode(params)
-
- try:
- res = make_post_request(url=url, data=params.encode("utf-8"))
-
- if res["ACK"][0] == "Failure":
- raise Exception
-
- except Exception:
- frappe.throw(_("Invalid payment gateway credentials"))
-
- def get_payment_url(self, **kwargs):
- setattr(self, "use_sandbox", cint(kwargs.get("use_sandbox", 0)))
-
- response = self.execute_set_express_checkout(**kwargs)
-
- if self.paypal_sandbox or self.use_sandbox:
- return_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"
- else:
- return_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"
-
- kwargs.update(
- {"token": response.get("TOKEN")[0], "correlation_id": response.get("CORRELATIONID")[0]}
- )
-
- create_request_log(kwargs, service_name="PayPal", name=kwargs["token"])
-
- return return_url.format(kwargs["token"])
-
- def execute_set_express_checkout(self, **kwargs):
- params, url = self.get_paypal_params_and_url()
-
- params.update(
- {
- "METHOD": "SetExpressCheckout",
- "returnUrl": get_url(f"{api_path}.get_express_checkout_details"),
- "cancelUrl": get_url("/payment-cancel"),
- "PAYMENTREQUEST_0_PAYMENTACTION": "SALE",
- "PAYMENTREQUEST_0_AMT": kwargs["amount"],
- "PAYMENTREQUEST_0_CURRENCYCODE": kwargs["currency"].upper(),
- }
- )
-
- if kwargs.get("subscription_details"):
- self.configure_recurring_payments(params, kwargs)
-
- params = urlencode(params)
- response = make_post_request(url, data=params.encode("utf-8"))
-
- if response.get("ACK")[0] != "Success":
- frappe.throw(_("Looks like something is wrong with this site's Paypal configuration."))
-
- return response
-
- def configure_recurring_payments(self, params, kwargs):
- # removing the params as we have to setup rucurring payments
- for param in (
- "PAYMENTREQUEST_0_PAYMENTACTION",
- "PAYMENTREQUEST_0_AMT",
- "PAYMENTREQUEST_0_CURRENCYCODE",
- ):
- del params[param]
-
- params.update(
- {
- "L_BILLINGTYPE0": "RecurringPayments", # The type of billing agreement
- "L_BILLINGAGREEMENTDESCRIPTION0": kwargs["description"],
- }
- )
-
-
-def get_paypal_and_transaction_details(token):
- doc = frappe.get_doc("PayPal Settings")
- doc.setup_sandbox_env(token)
- params, url = doc.get_paypal_params_and_url()
-
- integration_request = frappe.get_doc("Integration Request", token)
- data = json.loads(integration_request.data)
-
- return data, params, url
-
-
-def setup_redirect(data, redirect_url, custom_redirect_to=None, redirect=True):
- redirect_to = data.get("redirect_to") or None
- redirect_message = data.get("redirect_message") or None
-
- if custom_redirect_to:
- redirect_to = custom_redirect_to
-
- if redirect_to:
- redirect_url += "&" + urlencode({"redirect_to": redirect_to})
- if redirect_message:
- redirect_url += "&" + urlencode({"redirect_message": redirect_message})
-
- # this is done so that functions called via hooks can update flags.redirect_to
- if redirect:
- frappe.local.response["type"] = "redirect"
- frappe.local.response["location"] = get_url(redirect_url)
-
-
-@frappe.whitelist(allow_guest=True, xss_safe=True)
-def get_express_checkout_details(token):
- try:
- doc = frappe.get_doc("PayPal Settings")
- doc.setup_sandbox_env(token)
-
- params, url = doc.get_paypal_params_and_url()
- params.update({"METHOD": "GetExpressCheckoutDetails", "TOKEN": token})
-
- response = make_post_request(url, data=params)
-
- if response.get("ACK")[0] != "Success":
- frappe.respond_as_web_page(
- _("Something went wrong"),
- _(
- "Looks like something went wrong during the transaction. Since we haven't confirmed the payment, Paypal will automatically refund you this amount. If it doesn't, please send us an email and mention the Correlation ID: {0}."
- ).format(response.get("CORRELATIONID", [None])[0]),
- indicator_color="red",
- http_status_code=frappe.ValidationError.http_status_code,
- )
-
- return
-
- doc = frappe.get_doc("Integration Request", token)
- update_integration_request_status(
- token,
- {"payerid": response.get("PAYERID")[0], "payer_email": response.get("EMAIL")[0]},
- "Authorized",
- doc=doc,
- )
-
- frappe.local.response["type"] = "redirect"
- frappe.local.response["location"] = get_redirect_uri(doc, token, response.get("PAYERID")[0])
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
-
-@frappe.whitelist(allow_guest=True, xss_safe=True)
-def confirm_payment(token):
- try:
- custom_redirect_to = None
- data, params, url = get_paypal_and_transaction_details(token)
-
- params.update(
- {
- "METHOD": "DoExpressCheckoutPayment",
- "PAYERID": data.get("payerid"),
- "TOKEN": token,
- "PAYMENTREQUEST_0_PAYMENTACTION": "SALE",
- "PAYMENTREQUEST_0_AMT": data.get("amount"),
- "PAYMENTREQUEST_0_CURRENCYCODE": data.get("currency").upper(),
- }
- )
-
- response = make_post_request(url, data=params)
-
- if response.get("ACK")[0] == "Success":
- update_integration_request_status(
- token,
- {
- "transaction_id": response.get("PAYMENTINFO_0_TRANSACTIONID")[0],
- "correlation_id": response.get("CORRELATIONID")[0],
- },
- "Completed",
- )
-
- if data.get("reference_doctype") and data.get("reference_docname"):
- custom_redirect_to = frappe.get_doc(
- data.get("reference_doctype"), data.get("reference_docname")
- ).run_method("on_payment_authorized", "Completed")
- frappe.db.commit()
-
- redirect_url = "/integrations/payment-success?doctype={}&docname={}".format(
- data.get("reference_doctype"), data.get("reference_docname")
- )
- else:
- redirect_url = "/integrations/payment-failed"
-
- setup_redirect(data, redirect_url, custom_redirect_to)
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
-
-@frappe.whitelist(allow_guest=True, xss_safe=True)
-def create_recurring_profile(token, payerid):
- try:
- custom_redirect_to = None
- updating = False
- data, params, url = get_paypal_and_transaction_details(token)
-
- addons = data.get("addons")
- subscription_details = data.get("subscription_details")
-
- if data.get("subscription_id"):
- if addons:
- updating = True
- manage_recurring_payment_profile_status(data["subscription_id"], "Cancel", params, url)
-
- params.update(
- {
- "METHOD": "CreateRecurringPaymentsProfile",
- "PAYERID": payerid,
- "TOKEN": token,
- "DESC": data.get("description"),
- "BILLINGPERIOD": subscription_details.get("billing_period"),
- "BILLINGFREQUENCY": subscription_details.get("billing_frequency"),
- "AMT": data.get("amount")
- if data.get("subscription_amount") == data.get("amount")
- else data.get("subscription_amount"),
- "CURRENCYCODE": data.get("currency").upper(),
- "INITAMT": data.get("upfront_amount"),
- }
- )
-
- status_changed_to = "Completed" if data.get("starting_immediately") or updating else "Verified"
-
- starts_at = get_datetime(subscription_details.get("start_date")) or frappe.utils.now_datetime()
- starts_at = starts_at.replace(tzinfo=pytz.timezone(frappe.utils.get_time_zone())).astimezone(
- pytz.utc
- )
-
- # "PROFILESTARTDATE": datetime.utcfromtimestamp(get_timestamp(starts_at)).isoformat()
- params.update({"PROFILESTARTDATE": starts_at.isoformat()})
-
- response = make_post_request(url, data=params)
-
- if response.get("ACK")[0] == "Success":
- update_integration_request_status(
- token,
- {
- "profile_id": response.get("PROFILEID")[0],
- },
- "Completed",
- )
-
- if data.get("reference_doctype") and data.get("reference_docname"):
- data["subscription_id"] = response.get("PROFILEID")[0]
-
- frappe.flags.data = data
- custom_redirect_to = frappe.get_doc(
- data.get("reference_doctype"), data.get("reference_docname")
- ).run_method("on_payment_authorized", status_changed_to)
- frappe.db.commit()
-
- redirect_url = "/integrations/payment-success?doctype={}&docname={}".format(
- data.get("reference_doctype"), data.get("reference_docname")
- )
- else:
- redirect_url = "/integrations/payment-failed"
-
- setup_redirect(data, redirect_url, custom_redirect_to)
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
-
-def update_integration_request_status(token, data, status, error=False, doc=None):
- if not doc:
- doc = frappe.get_doc("Integration Request", token)
-
- doc.update_status(data, status)
-
-
-def get_redirect_uri(doc, token, payerid):
- data = json.loads(doc.data)
-
- if data.get("subscription_details") or data.get("subscription_id"):
- return get_url(f"{api_path}.create_recurring_profile?token={token}&payerid={payerid}")
- else:
- return get_url(f"{api_path}.confirm_payment?token={token}")
-
-
-def manage_recurring_payment_profile_status(profile_id, action, args, url):
- args.update(
- {"METHOD": "ManageRecurringPaymentsProfileStatus", "PROFILEID": profile_id, "ACTION": action}
- )
-
- response = make_post_request(url, data=args)
-
- # error code 11556 indicates profile is not in active state(or already cancelled)
- # thus could not cancel the subscription.
- # thus raise an exception only if the error code is not equal to 11556
-
- if response.get("ACK")[0] != "Success" and response.get("L_ERRORCODE0", [])[0] != "11556":
- frappe.throw(_("Failed while amending subscription"))
-
-
-@frappe.whitelist(allow_guest=True)
-def ipn_handler():
- try:
- data = frappe.local.form_dict
-
- validate_ipn_request(data)
-
- data.update({"payment_gateway": "PayPal"})
-
- doc = frappe.get_doc(
- {
- "data": json.dumps(frappe.local.form_dict),
- "doctype": "Integration Request",
- "request_description": "Subscription Notification",
- "is_remote_request": 1,
- "status": "Queued",
- }
- ).insert(ignore_permissions=True)
- frappe.db.commit()
-
- frappe.enqueue(
- method="frappe.integrations.doctype.paypal_settings.paypal_settings.handle_subscription_notification",
- queue="long",
- timeout=600,
- is_async=True,
- **{"doctype": "Integration Request", "docname": doc.name},
- )
-
- except frappe.InvalidStatusError:
- pass
- except Exception as e:
- frappe.log(frappe.log_error(title=e))
-
-
-def validate_ipn_request(data):
- def _throw():
- frappe.throw(_("In Valid Request"), exc=frappe.InvalidStatusError)
-
- if not data.get("recurring_payment_id"):
- _throw()
-
- doc = frappe.get_doc("PayPal Settings")
- params, url = doc.get_paypal_params_and_url()
-
- params.update(
- {"METHOD": "GetRecurringPaymentsProfileDetails", "PROFILEID": data.get("recurring_payment_id")}
- )
-
- params = urlencode(params)
- res = make_post_request(url=url, data=params.encode("utf-8"))
-
- if res["ACK"][0] != "Success":
- _throw()
-
-
-def handle_subscription_notification(doctype, docname):
- call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname)
diff --git a/frappe/integrations/doctype/paytm_settings/__init__.py b/frappe/integrations/doctype/paytm_settings/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/integrations/doctype/paytm_settings/paytm_settings.js b/frappe/integrations/doctype/paytm_settings/paytm_settings.js
deleted file mode 100644
index fe2ee7c952..0000000000
--- a/frappe/integrations/doctype/paytm_settings/paytm_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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')}`]));
- }
-});
diff --git a/frappe/integrations/doctype/paytm_settings/paytm_settings.json b/frappe/integrations/doctype/paytm_settings/paytm_settings.json
deleted file mode 100644
index 93fbd0df09..0000000000
--- a/frappe/integrations/doctype/paytm_settings/paytm_settings.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "actions": [],
- "creation": "2020-04-02 00:11:22.846697",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "merchant_id",
- "merchant_key",
- "staging",
- "column_break_4",
- "industry_type_id",
- "website"
- ],
- "fields": [
- {
- "fieldname": "merchant_id",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Merchant ID",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
- },
- {
- "fieldname": "merchant_key",
- "fieldtype": "Password",
- "in_list_view": 1,
- "label": "Merchant Key",
- "reqd": 1,
- "show_days": 1,
- "show_seconds": 1
- },
- {
- "default": "0",
- "fieldname": "staging",
- "fieldtype": "Check",
- "label": "Staging",
- "show_days": 1,
- "show_seconds": 1
- },
- {
- "depends_on": "eval: !doc.staging",
- "fieldname": "website",
- "fieldtype": "Data",
- "label": "Website",
- "mandatory_depends_on": "eval: !doc.staging",
- "show_days": 1,
- "show_seconds": 1
- },
- {
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "show_days": 1,
- "show_seconds": 1
- },
- {
- "depends_on": "eval: !doc.staging",
- "fieldname": "industry_type_id",
- "fieldtype": "Data",
- "label": "Industry Type ID",
- "mandatory_depends_on": "eval: !doc.staging",
- "show_days": 1,
- "show_seconds": 1
- }
- ],
- "issingle": 1,
- "links": [],
- "modified": "2020-06-08 13:36:09.703143",
- "modified_by": "Administrator",
- "module": "Integrations",
- "name": "Paytm Settings",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 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/frappe/integrations/doctype/paytm_settings/paytm_settings.py b/frappe/integrations/doctype/paytm_settings/paytm_settings.py
deleted file mode 100644
index 81a5f45f47..0000000000
--- a/frappe/integrations/doctype/paytm_settings/paytm_settings.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# Copyright (c) 2020, Frappe Technologies and contributors
-# License: MIT. See LICENSE
-
-import json
-from urllib.parse import urlencode
-
-import requests
-from paytmchecksum import generateSignature, verifySignature
-
-import frappe
-from frappe import _
-from frappe.integrations.utils import create_payment_gateway, create_request_log
-from frappe.model.document import Document
-from frappe.utils import call_hook_method, cint, cstr, flt, get_request_site_address, get_url
-from frappe.utils.password import get_decrypted_password
-
-
-class PaytmSettings(Document):
- supported_currencies = ["INR"]
-
- def validate(self):
- create_payment_gateway("Paytm")
- call_hook_method("payment_gateway_enabled", gateway="Paytm")
-
- def validate_transaction_currency(self, currency):
- if currency not in self.supported_currencies:
- frappe.throw(
- _(
- "Please select another payment method. Paytm does not support transactions in currency '{0}'"
- ).format(currency)
- )
-
- def get_payment_url(self, **kwargs):
- """Return payment url with several params"""
- # create unique order id by making it equal to the integration request
- integration_request = create_request_log(kwargs, service_name="Paytm")
- kwargs.update(dict(order_id=integration_request.name))
-
- return get_url(f"./integrations/paytm_checkout?{urlencode(kwargs)}")
-
-
-def get_paytm_config():
- """Returns paytm config"""
-
- paytm_config = frappe.db.get_singles_dict("Paytm Settings")
- paytm_config.update(
- dict(merchant_key=get_decrypted_password("Paytm Settings", "Paytm Settings", "merchant_key"))
- )
-
- if cint(paytm_config.staging):
- paytm_config.update(
- dict(
- website="WEBSTAGING",
- url="https://securegw-stage.paytm.in/order/process",
- transaction_status_url="https://securegw-stage.paytm.in/order/status",
- industry_type_id="RETAIL",
- )
- )
- else:
- paytm_config.update(
- dict(
- url="https://securegw.paytm.in/order/process",
- transaction_status_url="https://securegw.paytm.in/order/status",
- )
- )
- return paytm_config
-
-
-def get_paytm_params(payment_details, order_id, paytm_config):
-
- # initialize a dictionary
- paytm_params = dict()
-
- redirect_uri = (
- get_request_site_address(True)
- + "/api/method/frappe.integrations.doctype.paytm_settings.paytm_settings.verify_transaction"
- )
-
- paytm_params.update(
- {
- "MID": paytm_config.merchant_id,
- "WEBSITE": paytm_config.website,
- "INDUSTRY_TYPE_ID": paytm_config.industry_type_id,
- "CHANNEL_ID": "WEB",
- "ORDER_ID": order_id,
- "CUST_ID": payment_details["payer_email"],
- "EMAIL": payment_details["payer_email"],
- "TXN_AMOUNT": cstr(flt(payment_details["amount"], 2)),
- "CALLBACK_URL": redirect_uri,
- }
- )
-
- checksum = generateSignature(paytm_params, paytm_config.merchant_key)
-
- paytm_params.update({"CHECKSUMHASH": checksum})
-
- return paytm_params
-
-
-@frappe.whitelist(allow_guest=True)
-def verify_transaction(**paytm_params):
- """Verify checksum for received data in the callback and then verify the transaction"""
- paytm_config = get_paytm_config()
- is_valid_checksum = False
-
- paytm_params.pop("cmd", None)
- paytm_checksum = paytm_params.pop("CHECKSUMHASH", None)
-
- if paytm_params and paytm_config and paytm_checksum:
- # Verify checksum
- is_valid_checksum = verifySignature(paytm_params, paytm_config.merchant_key, paytm_checksum)
-
- if is_valid_checksum and paytm_params.get("RESPCODE") == "01":
- verify_transaction_status(paytm_config, paytm_params["ORDERID"])
- else:
- frappe.respond_as_web_page(
- "Payment Failed",
- "Transaction failed to complete. In case of any deductions, deducted amount will get refunded to your account.",
- http_status_code=401,
- indicator_color="red",
- )
- frappe.log_error(
- "Order unsuccessful. Failed Response:" + cstr(paytm_params), "Paytm Payment Failed"
- )
-
-
-def verify_transaction_status(paytm_config, order_id):
- """Verify transaction completion after checksum has been verified"""
- paytm_params = dict(MID=paytm_config.merchant_id, ORDERID=order_id)
-
- checksum = generateSignature(paytm_params, paytm_config.merchant_key)
- paytm_params["CHECKSUMHASH"] = checksum
-
- post_data = json.dumps(paytm_params)
- url = paytm_config.transaction_status_url
-
- response = requests.post(url, data=post_data, headers={"Content-type": "application/json"}).json()
- finalize_request(order_id, response)
-
-
-def finalize_request(order_id, transaction_response):
- request = frappe.get_doc("Integration Request", order_id)
- transaction_data = frappe._dict(json.loads(request.data))
- redirect_to = transaction_data.get("redirect_to") or None
- redirect_message = transaction_data.get("redirect_message") or None
-
- if transaction_response["STATUS"] == "TXN_SUCCESS":
- if transaction_data.reference_doctype and transaction_data.reference_docname:
- custom_redirect_to = None
- try:
- custom_redirect_to = frappe.get_doc(
- transaction_data.reference_doctype, transaction_data.reference_docname
- ).run_method("on_payment_authorized", "Completed")
- request.db_set("status", "Completed")
- except Exception:
- request.db_set("status", "Failed")
- frappe.log_error(frappe.get_traceback())
-
- if custom_redirect_to:
- redirect_to = custom_redirect_to
-
- redirect_url = "/integrations/payment-success"
- else:
- request.db_set("status", "Failed")
- redirect_url = "/integrations/payment-failed"
-
- if redirect_to:
- redirect_url += "?" + urlencode({"redirect_to": redirect_to})
- if redirect_message:
- redirect_url += "&" + urlencode({"redirect_message": redirect_message})
-
- frappe.local.response["type"] = "redirect"
- frappe.local.response["location"] = redirect_url
-
-
-def get_gateway_controller(doctype, docname):
- reference_doc = frappe.get_doc(doctype, docname)
- gateway_controller = frappe.db.get_value(
- "Payment Gateway", reference_doc.payment_gateway, "gateway_controller"
- )
- return gateway_controller
diff --git a/frappe/integrations/doctype/paytm_settings/test_paytm_settings.py b/frappe/integrations/doctype/paytm_settings/test_paytm_settings.py
deleted file mode 100644
index 91b69d5aec..0000000000
--- a/frappe/integrations/doctype/paytm_settings/test_paytm_settings.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (c) 2020, Frappe Technologies and Contributors
-# License: MIT. See LICENSE
-# import frappe
-import unittest
-
-
-class TestPaytmSettings(unittest.TestCase):
- pass
diff --git a/frappe/integrations/doctype/razorpay_settings/__init__.py b/frappe/integrations/doctype/razorpay_settings/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.js b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.js
deleted file mode 100644
index 6915c5c582..0000000000
--- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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
diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.json b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.json
deleted file mode 100644
index 3fdea79e2b..0000000000
--- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.json
+++ /dev/null
@@ -1,145 +0,0 @@
-{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-09-20 03:44:03.799402",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "System",
- "editable_grid": 1,
- "fields": [
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "api_key",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "API Key",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "api_secret",
- "fieldtype": "Password",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "API Secret",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Mention transaction completion page URL",
- "fieldname": "redirect_to",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Redirect To",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 1,
-
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-12-29 14:40:31.658270",
- "modified_by": "Administrator",
- "module": "Integrations",
- "name": "Razorpay Settings",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 1,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py
deleted file mode 100644
index a79e626b49..0000000000
--- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py
+++ /dev/null
@@ -1,530 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies and contributors
-# License: MIT. See LICENSE
-
-"""
-# Integrating RazorPay
-
-### Validate Currency
-
-Example:
-
- from frappe.integrations.utils import get_payment_gateway_controller
-
- controller = get_payment_gateway_controller("Razorpay")
- controller().validate_transaction_currency(currency)
-
-### 2. Redirect for payment
-
-Example:
-
- payment_details = {
- "amount": 600,
- "title": "Payment for bill : 111",
- "description": "payment via cart",
- "reference_doctype": "Payment Request",
- "reference_docname": "PR0001",
- "payer_email": "NuranVerkleij@example.com",
- "payer_name": "Nuran Verkleij",
- "order_id": "111",
- "currency": "INR",
- "payment_gateway": "Razorpay",
- "subscription_details": {
- "plan_id": "plan_12313", # if Required
- "start_date": "2018-08-30",
- "billing_period": "Month" #(Day, Week, Month, Year),
- "billing_frequency": 1,
- "customer_notify": 1,
- "upfront_amount": 1000
- }
- }
-
- # Redirect the user to this url
- url = controller().get_payment_url(**payment_details)
-
-
-### 3. On Completion of Payment
-
-Write a method for `on_payment_authorized` in the reference doctype
-
-Example:
-
- def on_payment_authorized(payment_status):
- # this method will be called when payment is complete
-
-
-##### Notes:
-
-payment_status - payment gateway will put payment status on callback.
-For razorpay payment status is Authorized
-
-"""
-
-import hashlib
-import hmac
-import json
-from urllib.parse import urlencode
-
-import razorpay
-
-import frappe
-from frappe import _
-from frappe.integrations.utils import (
- create_payment_gateway,
- create_request_log,
- make_get_request,
- make_post_request,
-)
-from frappe.model.document import Document
-from frappe.utils import call_hook_method, cint, get_timestamp, get_url
-
-
-class RazorpaySettings(Document):
- supported_currencies = ["INR"]
-
- def init_client(self):
- if self.api_key:
- secret = self.get_password(fieldname="api_secret", raise_exception=False)
- self.client = razorpay.Client(auth=(self.api_key, secret))
-
- def validate(self):
- create_payment_gateway("Razorpay")
- call_hook_method("payment_gateway_enabled", gateway="Razorpay")
- if not self.flags.ignore_mandatory:
- self.validate_razorpay_credentails()
-
- def validate_razorpay_credentails(self):
- if self.api_key and self.api_secret:
- try:
- make_get_request(
- url="https://api.razorpay.com/v1/payments",
- auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)),
- )
- except Exception:
- frappe.throw(_("Seems API Key or API Secret is wrong !!!"))
-
- def validate_transaction_currency(self, currency):
- if currency not in self.supported_currencies:
- frappe.throw(
- _(
- "Please select another payment method. Razorpay does not support transactions in currency '{0}'"
- ).format(currency)
- )
-
- def setup_addon(self, settings, **kwargs):
- """
- Addon template:
- {
- "item": {
- "name": row.upgrade_type,
- "amount": row.amount,
- "currency": currency,
- "description": "add-on description"
- },
- "quantity": 1 (The total amount is calculated as item.amount * quantity)
- }
- """
- url = "https://api.razorpay.com/v1/subscriptions/{}/addons".format(kwargs.get("subscription_id"))
-
- try:
- if not frappe.conf.converted_rupee_to_paisa:
- convert_rupee_to_paisa(**kwargs)
-
- for addon in kwargs.get("addons"):
- resp = make_post_request(
- url,
- auth=(settings.api_key, settings.api_secret),
- data=json.dumps(addon),
- headers={"content-type": "application/json"},
- )
- if not resp.get("id"):
- frappe.log_error(message=str(resp), title="Razorpay Failed while creating subscription")
- except Exception:
- frappe.log_error()
- # failed
- pass
-
- def setup_subscription(self, settings, **kwargs):
- start_date = (
- get_timestamp(kwargs.get("subscription_details").get("start_date"))
- if kwargs.get("subscription_details").get("start_date")
- else None
- )
-
- subscription_details = {
- "plan_id": kwargs.get("subscription_details").get("plan_id"),
- "total_count": kwargs.get("subscription_details").get("billing_frequency"),
- "customer_notify": kwargs.get("subscription_details").get("customer_notify"),
- }
-
- if start_date:
- subscription_details["start_at"] = cint(start_date)
-
- if kwargs.get("addons"):
- convert_rupee_to_paisa(**kwargs)
- subscription_details.update({"addons": kwargs.get("addons")})
-
- try:
- resp = make_post_request(
- "https://api.razorpay.com/v1/subscriptions",
- auth=(settings.api_key, settings.api_secret),
- data=json.dumps(subscription_details),
- headers={"content-type": "application/json"},
- )
-
- if resp.get("status") == "created":
- kwargs["subscription_id"] = resp.get("id")
- frappe.flags.status = "created"
- return kwargs
- else:
- frappe.log_error(message=str(resp), title="Razorpay Failed while creating subscription")
-
- except Exception:
- frappe.log_error()
-
- def prepare_subscription_details(self, settings, **kwargs):
- if not kwargs.get("subscription_id"):
- kwargs = self.setup_subscription(settings, **kwargs)
-
- if frappe.flags.status != "created":
- kwargs["subscription_id"] = None
-
- return kwargs
-
- def get_payment_url(self, **kwargs):
- integration_request = create_request_log(kwargs, service_name="Razorpay")
- return get_url(f"./integrations/razorpay_checkout?token={integration_request.name}")
-
- def create_order(self, **kwargs):
- # Creating Orders https://razorpay.com/docs/api/orders/
-
- # convert rupees to paisa
- kwargs["amount"] *= 100
-
- # Create integration log
- integration_request = create_request_log(kwargs, service_name="Razorpay")
-
- # Setup payment options
- payment_options = {
- "amount": kwargs.get("amount"),
- "currency": kwargs.get("currency", "INR"),
- "receipt": kwargs.get("receipt"),
- "payment_capture": kwargs.get("payment_capture"),
- }
- if self.api_key and self.api_secret:
- try:
- order = make_post_request(
- "https://api.razorpay.com/v1/orders",
- auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False)),
- data=payment_options,
- )
- order["integration_request"] = integration_request.name
- return order # Order returned to be consumed by razorpay.js
- except Exception:
- frappe.log(frappe.get_traceback())
- frappe.throw(_("Could not create razorpay order"))
-
- def create_request(self, data):
- self.data = frappe._dict(data)
-
- try:
- self.integration_request = frappe.get_doc("Integration Request", self.data.token)
- self.integration_request.update_status(self.data, "Queued")
- return self.authorize_payment()
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
- return {
- "redirect_to": frappe.redirect_to_message(
- _("Server Error"),
- _(
- "Seems issue with server's razorpay config. Don't worry, in case of failure amount will get refunded to your account."
- ),
- ),
- "status": 401,
- }
-
- 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
- until it is explicitly captured by merchant.
- """
- data = json.loads(self.integration_request.data)
- settings = self.get_settings(data)
-
- try:
- resp = make_get_request(
- f"https://api.razorpay.com/v1/payments/{self.data.razorpay_payment_id}",
- auth=(settings.api_key, settings.api_secret),
- )
-
- if resp.get("status") == "authorized":
- self.integration_request.update_status(data, "Authorized")
- self.flags.status_changed_to = "Authorized"
-
- if resp.get("status") == "captured":
- self.integration_request.update_status(data, "Completed")
- self.flags.status_changed_to = "Completed"
-
- elif data.get("subscription_id"):
- if resp.get("status") == "refunded":
- # if subscription start date is in future then
- # razorpay refunds the amount after authorizing the card details
- # thus changing status to Verified
-
- self.integration_request.update_status(data, "Completed")
- self.flags.status_changed_to = "Verified"
-
- else:
- frappe.log_error(message=str(resp), title="Razorpay Payment not authorized")
-
- except Exception:
- frappe.log_error()
-
- status = frappe.flags.integration_request.status_code
-
- redirect_to = data.get("redirect_to") or None
- redirect_message = data.get("redirect_message") or None
- if self.flags.status_changed_to in ("Authorized", "Verified", "Completed"):
- if self.data.reference_doctype and self.data.reference_docname:
- custom_redirect_to = None
- try:
- frappe.flags.data = data
- custom_redirect_to = frappe.get_doc(
- self.data.reference_doctype, self.data.reference_docname
- ).run_method("on_payment_authorized", self.flags.status_changed_to)
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
- if custom_redirect_to:
- redirect_to = custom_redirect_to
-
- redirect_url = "payment-success?doctype={}&docname={}".format(
- self.data.reference_doctype, self.data.reference_docname
- )
- else:
- redirect_url = "payment-failed"
-
- if redirect_to:
- redirect_url += "&" + urlencode({"redirect_to": redirect_to})
- if redirect_message:
- redirect_url += "&" + urlencode({"redirect_message": redirect_message})
-
- return {"redirect_to": redirect_url, "status": status}
-
- def get_settings(self, data):
- settings = frappe._dict(
- {
- "api_key": self.api_key,
- "api_secret": self.get_password(fieldname="api_secret", raise_exception=False),
- }
- )
-
- if cint(data.get("notes", {}).get("use_sandbox")) or data.get("use_sandbox"):
- settings.update(
- {
- "api_key": frappe.conf.sandbox_api_key,
- "api_secret": frappe.conf.sandbox_api_secret,
- }
- )
-
- return settings
-
- def cancel_subscription(self, subscription_id):
- settings = self.get_settings({})
-
- try:
- resp = make_post_request(
- f"https://api.razorpay.com/v1/subscriptions/{subscription_id}/cancel",
- auth=(settings.api_key, settings.api_secret),
- )
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
- def verify_signature(self, body, signature, key):
- key = bytes(key, "utf-8")
- body = bytes(body, "utf-8")
-
- dig = hmac.new(key=key, msg=body, digestmod=hashlib.sha256)
-
- generated_signature = dig.hexdigest()
- result = hmac.compare_digest(generated_signature, signature)
-
- if not result:
- frappe.throw(_("Razorpay Signature Verification Failed"), exc=frappe.PermissionError)
-
- return result
-
-
-def capture_payment(is_sandbox=False, sanbox_response=None):
- """
- Verifies the purchase as complete by the merchant.
- After capture, the amount is transferred to the merchant within T+3 days
- where T is the day on which payment is captured.
-
- Note: Attempting to capture a payment whose status is not authorized will produce an error.
- """
- controller = frappe.get_doc("Razorpay Settings")
-
- for doc in frappe.get_all(
- "Integration Request",
- filters={"status": "Authorized", "integration_request_service": "Razorpay"},
- fields=["name", "data"],
- ):
- try:
- if is_sandbox:
- resp = sanbox_response
- else:
- data = json.loads(doc.data)
- settings = controller.get_settings(data)
-
- resp = make_get_request(
- "https://api.razorpay.com/v1/payments/{}".format(data.get("razorpay_payment_id")),
- auth=(settings.api_key, settings.api_secret),
- data={"amount": data.get("amount")},
- )
-
- if resp.get("status") == "authorized":
- resp = make_post_request(
- "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")},
- )
-
- if resp.get("status") == "captured":
- frappe.db.set_value("Integration Request", doc.name, "status", "Completed")
-
- except Exception:
- doc = frappe.get_doc("Integration Request", doc.name)
- doc.status = "Failed"
- doc.error = frappe.get_traceback()
- doc.save()
- frappe.log_error(doc.error, f"{doc.name} Failed")
-
-
-@frappe.whitelist(allow_guest=True)
-def get_api_key():
- controller = frappe.get_doc("Razorpay Settings")
- return controller.api_key
-
-
-@frappe.whitelist(allow_guest=True)
-def get_order(doctype, docname):
- # Order returned to be consumed by razorpay.js
- doc = frappe.get_doc(doctype, docname)
- try:
- # Do not use run_method here as it fails silently
- return doc.get_razorpay_order()
- except AttributeError:
- frappe.log_error(frappe.get_traceback(), _("Controller method get_razorpay_order missing"))
- frappe.throw(_("Could not create Razorpay order. Please contact Administrator"))
-
-
-@frappe.whitelist(allow_guest=True)
-def order_payment_success(integration_request, params):
- """Called by razorpay.js on order payment success, the params
- contains razorpay_payment_id, razorpay_order_id, razorpay_signature
- that is updated in the data field of integration request
-
- Args:
- integration_request (string): Name for integration request doc
- params (string): Params to be updated for integration request.
- """
- params = json.loads(params)
- integration = frappe.get_doc("Integration Request", integration_request)
-
- # Update integration request
- integration.update_status(params, integration.status)
- integration.reload()
-
- data = json.loads(integration.data)
- controller = frappe.get_doc("Razorpay Settings")
-
- # Update payment and integration data for payment controller object
- controller.integration_request = integration
- controller.data = frappe._dict(data)
-
- # Authorize payment
- controller.authorize_payment()
-
-
-@frappe.whitelist(allow_guest=True)
-def order_payment_failure(integration_request, params):
- """Called by razorpay.js on failure
-
- Args:
- integration_request (TYPE): Description
- params (TYPE): error data to be updated
- """
- frappe.log_error(params, "Razorpay Payment Failure")
- params = json.loads(params)
- integration = frappe.get_doc("Integration Request", integration_request)
- integration.update_status(params, integration.status)
-
-
-def convert_rupee_to_paisa(**kwargs):
- for addon in kwargs.get("addons"):
- addon["item"]["amount"] *= 100
-
- frappe.conf.converted_rupee_to_paisa = True
-
-
-@frappe.whitelist(allow_guest=True)
-def razorpay_subscription_callback():
- try:
- data = frappe.local.form_dict
-
- validate_payment_callback(data)
-
- data.update({"payment_gateway": "Razorpay"})
-
- doc = frappe.get_doc(
- {
- "data": json.dumps(frappe.local.form_dict),
- "doctype": "Integration Request",
- "request_description": "Subscription Notification",
- "is_remote_request": 1,
- "status": "Queued",
- }
- ).insert(ignore_permissions=True)
- frappe.db.commit()
-
- frappe.enqueue(
- method="frappe.integrations.doctype.razorpay_settings.razorpay_settings.handle_subscription_notification",
- queue="long",
- timeout=600,
- is_async=True,
- **{"doctype": "Integration Request", "docname": doc.name},
- )
-
- except frappe.InvalidStatusError:
- pass
- except Exception as e:
- frappe.log(frappe.log_error(title=e))
-
-
-def validate_payment_callback(data):
- def _throw():
- frappe.throw(_("Invalid Subscription"), exc=frappe.InvalidStatusError)
-
- subscription_id = data.get("payload").get("subscription").get("entity").get("id")
-
- if not (subscription_id):
- _throw()
-
- controller = frappe.get_doc("Razorpay Settings")
-
- settings = controller.get_settings(data)
-
- resp = make_get_request(
- f"https://api.razorpay.com/v1/subscriptions/{subscription_id}",
- auth=(settings.api_key, settings.api_secret),
- )
-
- if resp.get("status") != "active":
- _throw()
-
-
-def handle_subscription_notification(doctype, docname):
- call_hook_method("handle_subscription_notification", doctype=doctype, docname=docname)
diff --git a/frappe/integrations/doctype/stripe_settings/__init__.py b/frappe/integrations/doctype/stripe_settings/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/frappe/integrations/doctype/stripe_settings/stripe_settings.js b/frappe/integrations/doctype/stripe_settings/stripe_settings.js
deleted file mode 100644
index 578ae94906..0000000000
--- a/frappe/integrations/doctype/stripe_settings/stripe_settings.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2017, Frappe Technologies and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Stripe Settings', {
- refresh: function(frm) {
-
- }
-});
diff --git a/frappe/integrations/doctype/stripe_settings/stripe_settings.json b/frappe/integrations/doctype/stripe_settings/stripe_settings.json
deleted file mode 100644
index 306355319b..0000000000
--- a/frappe/integrations/doctype/stripe_settings/stripe_settings.json
+++ /dev/null
@@ -1,315 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "field:gateway_name",
- "beta": 0,
- "creation": "2017-03-09 17:18:29.458397",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "gateway_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Payment Gateway Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "publishable_key",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Publishable Key",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "secret_key",
- "fieldtype": "Password",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Secret Key",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "header_img",
- "fieldtype": "Attach Image",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Header Image",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_7",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "redirect_url",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Redirect URL",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-05-23 13:32:14.429916",
- "modified_by": "Administrator",
- "module": "Integrations",
- "name": "Stripe Settings",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/frappe/integrations/doctype/stripe_settings/stripe_settings.py b/frappe/integrations/doctype/stripe_settings/stripe_settings.py
deleted file mode 100644
index 8e1d383790..0000000000
--- a/frappe/integrations/doctype/stripe_settings/stripe_settings.py
+++ /dev/null
@@ -1,280 +0,0 @@
-# Copyright (c) 2017, Frappe Technologies and contributors
-# License: MIT. See LICENSE
-
-from urllib.parse import urlencode
-
-import frappe
-from frappe import _
-from frappe.integrations.utils import (
- create_payment_gateway,
- create_request_log,
- make_get_request,
- make_post_request,
-)
-from frappe.model.document import Document
-from frappe.utils import call_hook_method, cint, flt, get_url
-
-
-class StripeSettings(Document):
- supported_currencies = [
- "AED",
- "ALL",
- "ANG",
- "ARS",
- "AUD",
- "AWG",
- "BBD",
- "BDT",
- "BIF",
- "BMD",
- "BND",
- "BOB",
- "BRL",
- "BSD",
- "BWP",
- "BZD",
- "CAD",
- "CHF",
- "CLP",
- "CNY",
- "COP",
- "CRC",
- "CVE",
- "CZK",
- "DJF",
- "DKK",
- "DOP",
- "DZD",
- "EGP",
- "ETB",
- "EUR",
- "FJD",
- "FKP",
- "GBP",
- "GIP",
- "GMD",
- "GNF",
- "GTQ",
- "GYD",
- "HKD",
- "HNL",
- "HRK",
- "HTG",
- "HUF",
- "IDR",
- "ILS",
- "INR",
- "ISK",
- "JMD",
- "JPY",
- "KES",
- "KHR",
- "KMF",
- "KRW",
- "KYD",
- "KZT",
- "LAK",
- "LBP",
- "LKR",
- "LRD",
- "MAD",
- "MDL",
- "MNT",
- "MOP",
- "MRO",
- "MUR",
- "MVR",
- "MWK",
- "MXN",
- "MYR",
- "NAD",
- "NGN",
- "NIO",
- "NOK",
- "NPR",
- "NZD",
- "PAB",
- "PEN",
- "PGK",
- "PHP",
- "PKR",
- "PLN",
- "PYG",
- "QAR",
- "RUB",
- "SAR",
- "SBD",
- "SCR",
- "SEK",
- "SGD",
- "SHP",
- "SLL",
- "SOS",
- "STD",
- "SVC",
- "SZL",
- "THB",
- "TOP",
- "TTD",
- "TWD",
- "TZS",
- "UAH",
- "UGX",
- "USD",
- "UYU",
- "UZS",
- "VND",
- "VUV",
- "WST",
- "XAF",
- "XOF",
- "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,
- }
-
- def on_update(self):
- create_payment_gateway(
- "Stripe-" + self.gateway_name, settings="Stripe Settings", controller=self.gateway_name
- )
- call_hook_method("payment_gateway_enabled", gateway="Stripe-" + self.gateway_name)
- if not self.flags.ignore_mandatory:
- self.validate_stripe_credentails()
-
- def validate_stripe_credentails(self):
- if self.publishable_key and self.secret_key:
- header = {
- "Authorization": "Bearer {}".format(
- self.get_password(fieldname="secret_key", raise_exception=False)
- )
- }
- try:
- make_get_request(url="https://api.stripe.com/v1/charges", headers=header)
- except Exception:
- frappe.throw(_("Seems Publishable Key or Secret Key is wrong !!!"))
-
- def validate_transaction_currency(self, currency):
- if currency not in self.supported_currencies:
- frappe.throw(
- _(
- "Please select another payment method. Stripe does not support transactions in currency '{0}'"
- ).format(currency)
- )
-
- def validate_minimum_transaction_amount(self, currency, amount):
- if currency in self.currency_wise_minimum_charge_amount:
- if flt(amount) < self.currency_wise_minimum_charge_amount.get(currency, 0.0):
- frappe.throw(
- _("For currency {0}, the minimum transaction amount should be {1}").format(
- currency, self.currency_wise_minimum_charge_amount.get(currency, 0.0)
- )
- )
-
- def get_payment_url(self, **kwargs):
- return get_url(f"./integrations/stripe_checkout?{urlencode(kwargs)}")
-
- def create_request(self, data):
- import stripe
-
- self.data = frappe._dict(data)
- stripe.api_key = self.get_password(fieldname="secret_key", raise_exception=False)
- stripe.default_http_client = stripe.http_client.RequestsClient()
-
- try:
- self.integration_request = create_request_log(self.data, service_name="Stripe")
- return self.create_charge_on_stripe()
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
- return {
- "redirect_to": frappe.redirect_to_message(
- _("Server Error"),
- _(
- "It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account."
- ),
- ),
- "status": 401,
- }
-
- def create_charge_on_stripe(self):
- import stripe
-
- try:
- charge = stripe.Charge.create(
- amount=cint(flt(self.data.amount) * 100),
- currency=self.data.currency,
- source=self.data.stripe_token_id,
- description=self.data.description,
- receipt_email=self.data.payer_email,
- )
-
- if charge.captured == True:
- self.integration_request.db_set("status", "Completed", update_modified=False)
- self.flags.status_changed_to = "Completed"
-
- else:
- frappe.log_error(charge.failure_message, "Stripe Payment not completed")
-
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
- return self.finalize_request()
-
- def finalize_request(self):
- redirect_to = self.data.get("redirect_to") or None
- redirect_message = self.data.get("redirect_message") or None
- status = self.integration_request.status
-
- if self.flags.status_changed_to == "Completed":
- if self.data.reference_doctype and self.data.reference_docname:
- custom_redirect_to = None
- try:
- custom_redirect_to = frappe.get_doc(
- self.data.reference_doctype, self.data.reference_docname
- ).run_method("on_payment_authorized", self.flags.status_changed_to)
- except Exception:
- frappe.log_error(frappe.get_traceback())
-
- if custom_redirect_to:
- redirect_to = custom_redirect_to
-
- redirect_url = "payment-success"
-
- if self.redirect_url:
- redirect_url = self.redirect_url
- redirect_to = None
- else:
- redirect_url = "payment-failed"
-
- if redirect_to:
- redirect_url += "?" + urlencode({"redirect_to": redirect_to})
- if redirect_message:
- redirect_url += "&" + urlencode({"redirect_message": redirect_message})
-
- return {"redirect_to": redirect_url, "status": status}
-
-
-def get_gateway_controller(doctype, docname):
- reference_doc = frappe.get_doc(doctype, docname)
- gateway_controller = frappe.db.get_value(
- "Payment Gateway", reference_doc.payment_gateway, "gateway_controller"
- )
- return gateway_controller
diff --git a/frappe/integrations/doctype/stripe_settings/test_stripe_settings.py b/frappe/integrations/doctype/stripe_settings/test_stripe_settings.py
deleted file mode 100644
index eed87bfcaf..0000000000
--- a/frappe/integrations/doctype/stripe_settings/test_stripe_settings.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright (c) 2018, Frappe Technologies and Contributors
-# License: MIT. See LICENSE
-import unittest
-
-
-class TestStripeSettings(unittest.TestCase):
- pass
diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py
index f215a73dc6..5ae8965c83 100644
--- a/frappe/integrations/utils.py
+++ b/frappe/integrations/utils.py
@@ -96,54 +96,6 @@ def get_json(obj):
return obj if isinstance(obj, str) else frappe.as_json(obj, indent=1)
-def get_payment_gateway_controller(payment_gateway):
- """Return payment gateway controller"""
- gateway = frappe.get_doc("Payment Gateway", payment_gateway)
- if gateway.gateway_controller is None:
- try:
- return frappe.get_doc(f"{payment_gateway} Settings")
- except Exception:
- frappe.throw(_("{0} Settings not found").format(payment_gateway))
- else:
- try:
- return frappe.get_doc(gateway.gateway_settings, gateway.gateway_controller)
- except Exception:
- frappe.throw(_("{0} Settings not found").format(payment_gateway))
-
-
-@frappe.whitelist(allow_guest=True, xss_safe=True)
-def get_checkout_url(**kwargs):
- try:
- if kwargs.get("payment_gateway"):
- doc = frappe.get_doc("{} Settings".format(kwargs.get("payment_gateway")))
- return doc.get_payment_url(**kwargs)
- else:
- raise Exception
- except Exception:
- frappe.respond_as_web_page(
- _("Something went wrong"),
- _(
- "Looks like something is wrong with this site's payment gateway configuration. No payment has been made."
- ),
- indicator_color="red",
- http_status_code=frappe.ValidationError.http_status_code,
- )
-
-
-def create_payment_gateway(gateway, settings=None, controller=None):
- # NOTE: we don't translate Payment Gateway name because it is an internal doctype
- if not frappe.db.exists("Payment Gateway", gateway):
- payment_gateway = frappe.get_doc(
- {
- "doctype": "Payment Gateway",
- "gateway": gateway,
- "gateway_settings": settings,
- "gateway_controller": controller,
- }
- )
- payment_gateway.insert(ignore_permissions=True)
-
-
def json_handler(obj):
if isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)):
return str(obj)
diff --git a/frappe/integrations/workspace/integrations/integrations.json b/frappe/integrations/workspace/integrations/integrations.json
index bbd2e1199f..8d1dfd64af 100644
--- a/frappe/integrations/workspace/integrations/integrations.json
+++ b/frappe/integrations/workspace/integrations/integrations.json
@@ -1,6 +1,6 @@
{
"charts": [],
- "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Backup\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Google Services\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Authentication\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
+ "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Backup\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Google Services\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Authentication\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
"creation": "2020-03-02 15:16:18.714190",
"docstatus": 0,
"doctype": "Workspace",
@@ -106,11 +106,52 @@
{
"hidden": 0,
"is_query_report": 0,
- "label": "Authentication",
+ "label": "Settings",
"link_count": 0,
"onboard": 0,
"type": "Card Break"
},
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Webhook",
+ "link_count": 0,
+ "link_to": "Webhook",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Slack Webhook URL",
+ "link_count": 0,
+ "link_to": "Slack Webhook URL",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "SMS Settings",
+ "link_count": 0,
+ "link_to": "SMS Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Authentication",
+ "link_count": 4,
+ "onboard": 0,
+ "type": "Card Break"
+ },
{
"dependencies": "",
"hidden": 0,
@@ -154,119 +195,16 @@
"link_type": "DocType",
"onboard": 0,
"type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Payments",
- "link_count": 0,
- "onboard": 0,
- "type": "Card Break"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Braintree Settings",
- "link_count": 0,
- "link_to": "Braintree Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "PayPal Settings",
- "link_count": 0,
- "link_to": "PayPal Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Razorpay Settings",
- "link_count": 0,
- "link_to": "Razorpay Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Stripe Settings",
- "link_count": 0,
- "link_to": "Stripe Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Paytm Settings",
- "link_count": 0,
- "link_to": "Paytm Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "hidden": 0,
- "is_query_report": 0,
- "label": "Settings",
- "link_count": 0,
- "onboard": 0,
- "type": "Card Break"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Webhook",
- "link_count": 0,
- "link_to": "Webhook",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "Slack Webhook URL",
- "link_count": 0,
- "link_to": "Slack Webhook URL",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
- },
- {
- "dependencies": "",
- "hidden": 0,
- "is_query_report": 0,
- "label": "SMS Settings",
- "link_count": 0,
- "link_to": "SMS Settings",
- "link_type": "DocType",
- "onboard": 0,
- "type": "Link"
}
],
- "modified": "2022-01-13 17:39:01.292154",
+ "modified": "2022-07-23 18:00:28.805405",
"modified_by": "Administrator",
"module": "Integrations",
"name": "Integrations",
"owner": "Administrator",
"parent_page": "",
"public": 1,
+ "quick_lists": [],
"restrict_to_domain": "",
"roles": [],
"sequence_id": 15.0,
diff --git a/frappe/patches.txt b/frappe/patches.txt
index ee2eb0d2a1..0dce4b9f71 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -66,7 +66,6 @@ execute:frappe.delete_doc_if_exists('Page', 'user-permissions')
frappe.patches.v10_0.set_no_copy_to_workflow_state
frappe.patches.v10_0.increase_single_table_column_length
frappe.patches.v11_0.create_contact_for_user
-frappe.patches.v11_0.sync_stripe_settings_before_migrate
frappe.patches.v11_0.update_list_user_settings
frappe.patches.v11_0.rename_workflow_action_to_workflow_action_master #13-06-2018
frappe.patches.v11_0.rename_email_alert_to_notification #13-06-2018
@@ -196,6 +195,7 @@ frappe.patches.v14_0.clear_long_pending_stale_logs
frappe.patches.v14_0.log_settings_migration
frappe.patches.v14_0.setup_likes_from_feedback
frappe.patches.v14_0.update_webforms
+frappe.patches.v14_0.delete_payment_gateways
[post_model_sync]
frappe.patches.v14_0.drop_data_import_legacy
diff --git a/frappe/patches/v11_0/sync_stripe_settings_before_migrate.py b/frappe/patches/v11_0/sync_stripe_settings_before_migrate.py
deleted file mode 100644
index 019ecef67c..0000000000
--- a/frappe/patches/v11_0/sync_stripe_settings_before_migrate.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import frappe
-from frappe.utils.password import get_decrypted_password
-
-
-def execute():
- publishable_key = frappe.db.sql(
- "select value from tabSingles where doctype='Stripe Settings' and field='publishable_key'"
- )
- if publishable_key:
- secret_key = get_decrypted_password(
- "Stripe Settings", "Stripe Settings", fieldname="secret_key", raise_exception=False
- )
- if secret_key:
- frappe.reload_doc("integrations", "doctype", "stripe_settings")
- frappe.db.commit()
-
- settings = frappe.new_doc("Stripe Settings")
- settings.gateway_name = (
- frappe.db.get_value("Global Defaults", None, "default_company") or "Stripe Settings"
- )
- settings.publishable_key = publishable_key
- settings.secret_key = secret_key
- settings.save(ignore_permissions=True)
-
- frappe.db.delete("Singles", {"doctype": "Stripe Settings"})
diff --git a/frappe/patches/v14_0/delete_payment_gateways.py b/frappe/patches/v14_0/delete_payment_gateways.py
new file mode 100644
index 0000000000..c06f63a2d3
--- /dev/null
+++ b/frappe/patches/v14_0/delete_payment_gateways.py
@@ -0,0 +1,16 @@
+import frappe
+
+
+def execute():
+ if "payments" in frappe.get_installed_apps():
+ return
+
+ for doctype in (
+ "Payment Gateway",
+ "Razorpay Settings",
+ "Braintree Settings",
+ "PayPal Settings",
+ "Paytm Settings",
+ "Stripe Settings",
+ ):
+ frappe.delete_doc_if_exists("DocType", doctype, force=True)
diff --git a/frappe/printing/doctype/letter_head/letter_head.py b/frappe/printing/doctype/letter_head/letter_head.py
index 9edd84a425..c48fd1fe25 100644
--- a/frappe/printing/doctype/letter_head/letter_head.py
+++ b/frappe/printing/doctype/letter_head/letter_head.py
@@ -61,9 +61,12 @@ class LetterHead(Document):
# To preserve the aspect ratio of the image, apply constraints only on
# the greater dimension and allow the other to scale accordingly
- dimension = "width" if width > height else "height"
+ dimension = "width" if self.get(width) > self.get(height) else "height"
dimension_value = self.get(f"{dimension_prefix}{dimension}")
+ if not dimension_value:
+ dimension_value = ""
+
self.set(
html_field,
f"""
diff --git a/frappe/public/js/checkout.bundle.js b/frappe/public/js/checkout.bundle.js
deleted file mode 100644
index 954e838fa8..0000000000
--- a/frappe/public/js/checkout.bundle.js
+++ /dev/null
@@ -1 +0,0 @@
-import "./integrations/razorpay";
diff --git a/frappe/public/js/frappe/form/controls/text_editor.js b/frappe/public/js/frappe/form/controls/text_editor.js
index 50b625f248..be0983fc73 100644
--- a/frappe/public/js/frappe/form/controls/text_editor.js
+++ b/frappe/public/js/frappe/form/controls/text_editor.js
@@ -195,7 +195,9 @@ frappe.ui.form.ControlTextEditor = class ControlTextEditor extends frappe.ui.for
let values = await frappe.xcall(method, {
search_term
});
- renderList(values, search_term);
+
+ let sorted_values = me.prioritize_involved_users_in_mention(values);
+ renderList(sorted_values, search_term);
}, 300),
renderItem(item) {
let value = item.value;
@@ -204,6 +206,16 @@ frappe.ui.form.ControlTextEditor = class ControlTextEditor extends frappe.ui.for
};
}
+ prioritize_involved_users_in_mention(values) {
+ const involved_users = this.frm?.get_involved_users() // input on form
+ || cur_frm?.get_involved_users() // comment box / dialog on active form
+ || [];
+
+ return values
+ .filter(val => involved_users.includes(val.id))
+ .concat(values.filter(val => !involved_users.includes(val.id)));
+ }
+
get_toolbar_options() {
return [
[{ header: [1, 2, 3, false] }],
diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js
index 4e38a5ee7e..ea37c80e5e 100644
--- a/frappe/public/js/frappe/form/form.js
+++ b/frappe/public/js/frappe/form/form.js
@@ -1873,6 +1873,29 @@ frappe.ui.form.Form = class FrappeForm {
get_active_tab() {
return this.active_tab_map && this.active_tab_map[this.docname];
}
+
+ get_involved_users() {
+ let user_fields = this.meta.fields
+ .filter(d => d.fieldtype === 'Link' && d.options === 'User')
+ .map(d => d.fieldname);
+
+ user_fields = [...user_fields, "owner", "modified_by"];
+ let involved_users = user_fields.map(field => this.doc[field]);
+
+ const docinfo = this.get_docinfo();
+
+ involved_users = involved_users.concat(
+ docinfo.communications.map(d => d.sender && d.delivery_status === 'sent'),
+ docinfo.comments.map(d => d.owner),
+ docinfo.versions.map(d => d.owner),
+ docinfo.assignments.map(d => d.owner)
+ );
+
+ return involved_users
+ .uniqBy(u => u)
+ .filter(user => !['Administrator', frappe.session.user].includes(user))
+ .filter(Boolean);
+ }
};
frappe.validated = 0;
diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js
index 7bbe4b123a..6e8ee75ffd 100644
--- a/frappe/public/js/frappe/form/grid.js
+++ b/frappe/public/js/frappe/form/grid.js
@@ -298,15 +298,14 @@ export default class Grid {
show_search: true
});
- Object.keys(this.filter).length !== 0 &&
- this.update_search_columns();
+ this.filter_applied && this.update_search_columns();
}
update_search_columns() {
for (const field in this.filter) {
if (this.filter[field] && !this.header_search.search_columns[field]) {
delete this.filter[field];
- this.data = this.get_data(Object.keys(this.filter).length !== 0);
+ this.data = this.get_data(this.filter_applied);
break;
}
@@ -323,7 +322,8 @@ export default class Grid {
refresh() {
if (this.frm && this.frm.setting_dependency) return;
- this.data = this.get_data(Object.keys(this.filter).length !== 0);
+ this.filter_applied = Object.keys(this.filter).length !== 0;
+ this.data = this.get_data(this.filter_applied);
!this.wrapper && this.make();
let $rows = $(this.parent).find('.rows');
diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js
index a1c3dce91f..0d71b3b305 100644
--- a/frappe/public/js/frappe/form/grid_row.js
+++ b/frappe/public/js/frappe/form/grid_row.js
@@ -14,7 +14,7 @@ export default class GridRow {
make() {
var me = this;
- this.wrapper = $('
').appendTo(this.parent).data("grid_row", this);
+ this.wrapper = $('
');
this.row = $('
').appendTo(this.wrapper)
.on("click", function(e) {
if($(e.target).hasClass('grid-row-check') || $(e.target).hasClass('row-index') || $(e.target).parent().hasClass('row-index')) {
@@ -33,9 +33,9 @@ export default class GridRow {
} else {
this.render_row();
}
- if(this.doc) {
- this.set_data();
- }
+
+ this.set_data();
+ this.wrapper.appendTo(this.parent);
}
set_docfields(update=false) {
@@ -55,8 +55,9 @@ export default class GridRow {
set_data() {
this.wrapper.data({
- "doc": this.doc
- })
+ "grid_row": this,
+ "doc": this.doc || "",
+ });
}
set_row_index() {
if(this.doc) {
@@ -750,6 +751,7 @@ export default class GridRow {
.option('disabled', Object.keys(this.grid.filter).length !== 0);
this.grid.prevent_build = true;
+ this.grid.grid_pagination.go_to_page(1);
this.grid.refresh();
this.grid.prevent_build = false;
}, 500));
diff --git a/frappe/public/js/frappe/form/save.js b/frappe/public/js/frappe/form/save.js
index f1cb42250a..d1486ea5d7 100644
--- a/frappe/public/js/frappe/form/save.js
+++ b/frappe/public/js/frappe/form/save.js
@@ -156,7 +156,12 @@ frappe.ui.form.save = function (frm, action, callback, btn) {
if (error_fields.length) {
let meta = frappe.get_meta(doc.doctype);
if (meta.istable) {
- const table_label = __(frappe.meta.docfield_map[doc.parenttype][doc.parentfield].label).bold();
+ const table_field = frappe.meta.docfield_map[doc.parenttype][doc.parentfield];
+
+ const table_label = __(
+ table_field.label || frappe.unscrub(table_field.fieldname)
+ ).bold();
+
var message = __('Mandatory fields required in table {0}, Row {1}', [table_label, doc.idx]);
} else {
var message = __('Mandatory fields required in {0}', [__(doc.doctype)]);
diff --git a/frappe/public/js/frappe/form/sidebar/review.js b/frappe/public/js/frappe/form/sidebar/review.js
index 2d54ad4329..242f6f0435 100644
--- a/frappe/public/js/frappe/form/sidebar/review.js
+++ b/frappe/public/js/frappe/form/sidebar/review.js
@@ -38,30 +38,9 @@ frappe.ui.form.Review = class Review {
review_button.click(() => this.show_review_dialog());
}
}
- get_involved_users() {
- const user_fields = this.frm.meta.fields
- .filter(d => d.fieldtype === 'Link' && d.options === 'User')
- .map(d => d.fieldname);
- user_fields.push('owner');
- let involved_users = user_fields.map(field => this.frm.doc[field]);
-
- const docinfo = this.frm.get_docinfo();
-
- involved_users = involved_users.concat(
- docinfo.communications.map(d => d.sender && d.delivery_status === 'sent'),
- docinfo.comments.map(d => d.owner),
- docinfo.versions.map(d => d.owner),
- docinfo.assignments.map(d => d.owner)
- );
-
- return involved_users
- .uniqBy(u => u)
- .filter(user => !['Administrator', frappe.session.user].includes(user))
- .filter(Boolean);
- }
show_review_dialog() {
- const user_options = this.get_involved_users();
+ const user_options = this.frm.get_involved_users();
const review_dialog = new frappe.ui.Dialog({
'title': __('Add Review'),
'fields': [{
diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js
index e5272ccd91..912016d330 100644
--- a/frappe/public/js/frappe/list/base_list.js
+++ b/frappe/public/js/frappe/list/base_list.js
@@ -69,6 +69,14 @@ frappe.views.BaseList = class BaseList {
];
}
+ get_list_view_settings() {
+ return frappe
+ .call("frappe.desk.listview.get_list_settings", {
+ doctype: this.doctype,
+ })
+ .then((doc) => (this.list_view_settings = doc.message || {}));
+ }
+
setup_fields() {
this.set_fields();
this.build_fields();
diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js
index cbeda50e53..9c5dba3370 100644
--- a/frappe/public/js/frappe/list/list_view.js
+++ b/frappe/public/js/frappe/list/list_view.js
@@ -107,14 +107,6 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return this.get_list_view_settings();
}
- get_list_view_settings() {
- return frappe
- .call("frappe.desk.listview.get_list_settings", {
- doctype: this.doctype,
- })
- .then((doc) => (this.list_view_settings = doc.message || {}));
- }
-
on_sort_change(sort_by, sort_order) {
this.sort_by = sort_by;
this.sort_order = sort_order;
diff --git a/frappe/public/js/frappe/ui/filters/filter_list.js b/frappe/public/js/frappe/ui/filters/filter_list.js
index 5e13f086cb..6d90aaa7eb 100644
--- a/frappe/public/js/frappe/ui/filters/filter_list.js
+++ b/frappe/public/js/frappe/ui/filters/filter_list.js
@@ -31,7 +31,7 @@ frappe.ui.FilterGroup = class {
trigger: 'manual',
container: 'body',
placement: 'bottom',
- offset: '-100px 0'
+ offset: '-100px, 0'
});
}
diff --git a/frappe/public/js/frappe/ui/group_by/group_by.js b/frappe/public/js/frappe/ui/group_by/group_by.js
index 692d675c62..9625e1d2af 100644
--- a/frappe/public/js/frappe/ui/group_by/group_by.js
+++ b/frappe/public/js/frappe/ui/group_by/group_by.js
@@ -42,7 +42,7 @@ frappe.ui.GroupBy = class {
trigger: 'manual',
container: 'body',
placement: 'bottom',
- offset: '-100px 0',
+ offset: '-100px, 0',
});
}
diff --git a/frappe/public/js/frappe/ui/notifications/notifications.js b/frappe/public/js/frappe/ui/notifications/notifications.js
index bf1cee2cbf..90bf685b1b 100644
--- a/frappe/public/js/frappe/ui/notifications/notifications.js
+++ b/frappe/public/js/frappe/ui/notifications/notifications.js
@@ -189,19 +189,22 @@ class NotificationsView extends BaseNotificationsView {
);
this.setup_notification_listeners();
- this.get_notifications_list(this.max_length).then(list => {
- this.dropdown_items = list;
+ this.get_notifications_list(this.max_length).then(r => {
+ if (!r.message) return;
+ this.dropdown_items = r.message.notification_logs;
+ frappe.update_user_info(r.message.user_info);
this.render_notifications_dropdown();
- if (this.settings.seen == 0) {
+ if (this.settings.seen == 0 && this.dropdown_items.length > 0) {
this.toggle_notification_icon(false);
}
});
-
}
update_dropdown() {
this.get_notifications_list(1).then(r => {
- let new_item = r[0];
+ if (!r.message) return;
+ let new_item = r.message.notification_logs[0];
+ frappe.update_user_info(r.message.user_info);
this.dropdown_items.unshift(new_item);
if (this.dropdown_items.length > this.max_length) {
this.container
@@ -322,11 +325,10 @@ class NotificationsView extends BaseNotificationsView {
}
get_notifications_list(limit) {
- return frappe.db.get_list('Notification Log', {
- fields: ['*'],
- limit: limit,
- order_by: 'creation desc'
- });
+ return frappe.call(
+ 'frappe.desk.doctype.notification_log.notification_log.get_notification_logs',
+ { limit: limit }
+ );
}
get_item_link(notification_doc) {
diff --git a/frappe/public/js/frappe/ui/tree.js b/frappe/public/js/frappe/ui/tree.js
index c32d92aa32..4b2c0bc12b 100644
--- a/frappe/public/js/frappe/ui/tree.js
+++ b/frappe/public/js/frappe/ui/tree.js
@@ -134,7 +134,7 @@ frappe.ui.Tree = class {
}
reload_node(node) {
- this.load_children(node);
+ return this.load_children(node);
}
toggle() {
@@ -150,21 +150,20 @@ frappe.ui.Tree = class {
}
load_children(node, deep=false) {
- let lab = node.label, value = node.data.value, is_root = node.is_root;
+ const value = node.data.value,
+ is_root = node.is_root;
- if(!deep) {
- frappe.run_serially([
+ return deep
+ ? frappe.run_serially([
+ () => this.get_all_nodes(value, is_root, node.label),
+ data_list => this.render_children_of_all_nodes(data_list),
+ () => this.set_selected_node(node),
+ ])
+ : frappe.run_serially([
() => this.get_nodes(value, is_root),
- (data_set) => this.render_node_children(node, data_set),
- () => this.set_selected_node(node)
+ data_set => this.render_node_children(node, data_set),
+ () => this.set_selected_node(node),
]);
- } else {
- frappe.run_serially([
- () => this.get_all_nodes(value, is_root, lab),
- (data_list) => this.render_children_of_all_nodes(data_list),
- () => this.set_selected_node(node)
- ]);
- }
}
render_children_of_all_nodes(data_list) {
diff --git a/frappe/public/js/frappe/utils/user.js b/frappe/public/js/frappe/utils/user.js
index a5a7801cc1..e888fbcd9a 100644
--- a/frappe/public/js/frappe/utils/user.js
+++ b/frappe/public/js/frappe/utils/user.js
@@ -14,6 +14,16 @@ frappe.user_info = function(uid) {
return user_info;
};
+frappe.update_user_info = function(user_info) {
+ for (let user in user_info) {
+ if (frappe.boot.user_info[user]) {
+ Object.assign(frappe.boot.user_info[user], user_info[user]);
+ } else {
+ frappe.boot.user_info[user] = user_info[user];
+ }
+ }
+};
+
frappe.provide('frappe.user');
$.extend(frappe.user, {
diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js
index 2ea780c13d..945ec83439 100644
--- a/frappe/public/js/frappe/views/reports/report_view.js
+++ b/frappe/public/js/frappe/views/reports/report_view.js
@@ -43,6 +43,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
this.add_totals_row = this.view_user_settings.add_totals_row || 0;
this.chart_args = this.view_user_settings.chart_args;
}
+ return this.get_list_view_settings();
}
setup_view() {
@@ -53,6 +54,9 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
}
setup_events() {
+ if (this.list_view_settings?.disable_auto_refresh) {
+ return;
+ }
frappe.realtime.on("list_update", (data) => this.on_update(data));
}
@@ -216,6 +220,9 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
}
render_count() {
+ if (this.list_view_settings?.disable_count) {
+ return;
+ }
let $list_count = this.$paging_area.find('.list-count');
if (!$list_count.length) {
$list_count = $('
')
@@ -1540,6 +1547,12 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
});
}
+ if (frappe.user.has_role("System Manager")) {
+ if (this.get_view_settings) {
+ items.push(this.get_view_settings());
+ }
+ }
+
return items.map(i => Object.assign(i, { standard: true }));
}
diff --git a/frappe/public/js/frappe/web_form/web_form.js b/frappe/public/js/frappe/web_form/web_form.js
index 21d88eac49..8cb30be529 100644
--- a/frappe/public/js/frappe/web_form/web_form.js
+++ b/frappe/public/js/frappe/web_form/web_form.js
@@ -280,6 +280,7 @@ export default class WebForm extends frappe.ui.FieldGroup {
if (!doc_values) return;
if (window.saving) return;
+ // TODO: remove this (used for payments app)
let for_payment = Boolean(this.accept_payment && !this.doc.paid);
Object.assign(this.doc, doc_values);
@@ -342,6 +343,7 @@ export default class WebForm extends frappe.ui.FieldGroup {
}
handle_success(data) {
+ // TODO: remove this (used for payments app)
if (this.accept_payment && !this.doc.paid) {
window.location.href = data;
}
diff --git a/frappe/public/js/integrations/razorpay.js b/frappe/public/js/integrations/razorpay.js
deleted file mode 100644
index eda4ac1894..0000000000
--- a/frappe/public/js/integrations/razorpay.js
+++ /dev/null
@@ -1,148 +0,0 @@
-/* HOW-TO
-
-Razorpay Payment
-
-1. Include checkout script in your code
- {{ include_script('checkout.bundle.js) }}
-
-2. Create the Order controller in your backend
- def get_razorpay_order(self):
- controller = get_payment_gateway_controller("Razorpay")
-
- payment_details = {
- "amount": 300,
- ...
- "reference_doctype": "Conference Participant",
- "reference_docname": self.name,
- ...
- "receipt": self.name
- }
-
- return controller.create_order(**payment_details)
-
-3. Inititate the payment in client using checkout API
- function make_payment(ticket) {
- var options = {
- "name": "",
- "description": "",
- "image": "",
- "prefill": {
- "name": "",
- "email": "",
- "contact": ""
- },
- "theme": {
- "color": ""
- },
- "doctype": "",
- "docname": " {
-
-
-{% endblock %}
-
-{%- block page_content -%}
-
-
-
-
-
-

-
-
-
-
-
-
-
-
-
-{% endblock %}
diff --git a/frappe/templates/pages/integrations/braintree_checkout.py b/frappe/templates/pages/integrations/braintree_checkout.py
deleted file mode 100644
index c4c79ea74f..0000000000
--- a/frappe/templates/pages/integrations/braintree_checkout.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-
-import json
-
-import frappe
-from frappe import _
-from frappe.integrations.doctype.braintree_settings.braintree_settings import (
- get_client_token,
- get_gateway_controller,
-)
-from frappe.utils import flt
-
-no_cache = 1
-
-expected_keys = (
- "amount",
- "title",
- "description",
- "reference_doctype",
- "reference_docname",
- "payer_name",
- "payer_email",
- "order_id",
- "currency",
-)
-
-
-def get_context(context):
- context.no_cache = 1
-
- # all these keys exist in form_dict
- if not (set(expected_keys) - set(list(frappe.form_dict))):
- for key in expected_keys:
- context[key] = frappe.form_dict[key]
-
- context.client_token = get_client_token(context.reference_docname)
-
- 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"
- )
-
- else:
- frappe.redirect_to_message(
- _("Some information is missing"),
- _("Looks like someone sent you to an incomplete URL. Please ask them to look into it."),
- )
- frappe.local.flags.redirect_location = frappe.local.response.location
- raise frappe.Redirect
-
-
-@frappe.whitelist(allow_guest=True)
-def make_payment(payload_nonce, data, reference_doctype, reference_docname):
- data = json.loads(data)
-
- data.update({"payload_nonce": payload_nonce})
-
- gateway_controller = get_gateway_controller(reference_docname)
- data = frappe.get_doc("Braintree Settings", gateway_controller).create_payment_request(data)
- frappe.db.commit()
- return data
diff --git a/frappe/templates/pages/integrations/payment-cancel.html b/frappe/templates/pages/integrations/payment-cancel.html
deleted file mode 100644
index a7c327508f..0000000000
--- a/frappe/templates/pages/integrations/payment-cancel.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block title %}{{ _("Payment Cancelled") }}{% endblock %}
-
-{%- block page_content -%}
-
-
-
- {{ _("Payment Cancelled") }}
-
-
{{ _("Your payment is cancelled.") }}
-
-
-
-
-{% endblock %}
diff --git a/frappe/templates/pages/integrations/payment-failed.html b/frappe/templates/pages/integrations/payment-failed.html
deleted file mode 100644
index 8f416b563a..0000000000
--- a/frappe/templates/pages/integrations/payment-failed.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block title %}{{ _("Payment Failed") }}{% endblock %}
-
-{%- block page_content -%}
-
-
-
- {{ _("Payment Failed") }}
-
-
{{ _("Your payment has failed.") }}
-
-
-
-
-{% endblock %}
diff --git a/frappe/templates/pages/integrations/payment-success.html b/frappe/templates/pages/integrations/payment-success.html
deleted file mode 100644
index 76c5db93bf..0000000000
--- a/frappe/templates/pages/integrations/payment-success.html
+++ /dev/null
@@ -1,34 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block title %}{{ _("Payment Success") }}{% endblock %}
-
-{%- block page_content -%}
-
-
-
- {{ _("Success") }}
-
-
{{ payment_message or _("Your payment was successfully accepted") }}
- {% if not payment_message %}
-
- {% endif %}
-
-
-
-{% endblock %}
diff --git a/frappe/templates/pages/integrations/payment_cancel.py b/frappe/templates/pages/integrations/payment_cancel.py
deleted file mode 100644
index cf2a10f8c7..0000000000
--- a/frappe/templates/pages/integrations/payment_cancel.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-
-import frappe
-
-
-def get_context(context):
- token = frappe.local.form_dict.token
-
- if token:
- frappe.db.set_value("Integration Request", token, "status", "Cancelled")
- frappe.db.commit()
diff --git a/frappe/templates/pages/integrations/payment_success.py b/frappe/templates/pages/integrations/payment_success.py
deleted file mode 100644
index 8985850a81..0000000000
--- a/frappe/templates/pages/integrations/payment_success.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-
-import frappe
-
-no_cache = True
-
-
-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 = ""
- if hasattr(doc, "get_payment_success_message"):
- context.payment_message = doc.get_payment_success_message()
diff --git a/frappe/templates/pages/integrations/paytm_checkout.html b/frappe/templates/pages/integrations/paytm_checkout.html
deleted file mode 100644
index 168f6597e5..0000000000
--- a/frappe/templates/pages/integrations/paytm_checkout.html
+++ /dev/null
@@ -1,43 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block title %} Payment {% endblock %}
-
-{%- block header -%}
-
- Merchant Checkout Page
-
-{% endblock %}
-
-{% block script %}
-
-{% endblock %}
-
-{%- block page_content -%}
-
-
-
Please do not refresh this page...
-
-
-
-
-{% endblock %}
-
-{% block style %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/frappe/templates/pages/integrations/paytm_checkout.py b/frappe/templates/pages/integrations/paytm_checkout.py
deleted file mode 100644
index 93097e038b..0000000000
--- a/frappe/templates/pages/integrations/paytm_checkout.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-import json
-
-import frappe
-from frappe import _
-from frappe.integrations.doctype.paytm_settings.paytm_settings import (
- get_paytm_config,
- get_paytm_params,
-)
-
-
-def get_context(context):
- context.no_cache = 1
- paytm_config = get_paytm_config()
-
- try:
- doc = frappe.get_doc("Integration Request", frappe.form_dict["order_id"])
-
- context.payment_details = get_paytm_params(json.loads(doc.data), doc.name, paytm_config)
-
- context.url = paytm_config.url
-
- except Exception:
- frappe.log_error()
- frappe.redirect_to_message(
- _("Invalid Token"),
- _("Seems token you are using is invalid!"),
- http_status_code=400,
- indicator_color="red",
- )
-
- frappe.local.flags.redirect_location = frappe.local.response.location
- raise frappe.Redirect
diff --git a/frappe/templates/pages/integrations/razorpay_checkout.html b/frappe/templates/pages/integrations/razorpay_checkout.html
deleted file mode 100644
index fa1101c216..0000000000
--- a/frappe/templates/pages/integrations/razorpay_checkout.html
+++ /dev/null
@@ -1,28 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block title %} Payment {% endblock %}
-
-{%- block header -%}{% endblock %}
-
-{% block script %}
-
-
-{% endblock %}
-
-{%- block page_content -%}
-
-
- Loading Payment System
- Confirming Payment
-
-
-{% endblock %}
-
-{% block style %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/frappe/templates/pages/integrations/razorpay_checkout.py b/frappe/templates/pages/integrations/razorpay_checkout.py
deleted file mode 100644
index d0e77f6d8a..0000000000
--- a/frappe/templates/pages/integrations/razorpay_checkout.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-import json
-
-import frappe
-from frappe import _
-from frappe.utils import cint, flt
-
-no_cache = 1
-
-expected_keys = (
- "amount",
- "title",
- "description",
- "reference_doctype",
- "reference_docname",
- "payer_name",
- "payer_email",
- "order_id",
- "currency",
-)
-
-
-def get_context(context):
- context.no_cache = 1
- context.api_key = get_api_key()
-
- try:
- doc = frappe.get_doc("Integration Request", frappe.form_dict["token"])
- payment_details = json.loads(doc.data)
-
- for key in expected_keys:
- context[key] = payment_details[key]
-
- context["token"] = frappe.form_dict["token"]
- context["amount"] = flt(context["amount"])
- context["subscription_id"] = (
- payment_details["subscription_id"] if payment_details.get("subscription_id") else ""
- )
-
- except Exception as e:
- frappe.redirect_to_message(
- _("Invalid Token"),
- _("Seems token you are using is invalid!"),
- http_status_code=400,
- indicator_color="red",
- )
-
- frappe.local.flags.redirect_location = frappe.local.response.location
- raise frappe.Redirect
-
-
-def get_api_key():
- api_key = frappe.db.get_single_value("Razorpay Settings", "api_key")
- if cint(frappe.form_dict.get("use_sandbox")):
- api_key = frappe.conf.sandbox_api_key
-
- return api_key
-
-
-@frappe.whitelist(allow_guest=True)
-def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname, token):
- data = {}
-
- if isinstance(options, str):
- data = json.loads(options)
-
- data.update(
- {
- "razorpay_payment_id": razorpay_payment_id,
- "reference_docname": reference_docname,
- "reference_doctype": reference_doctype,
- "token": token,
- }
- )
-
- data = frappe.get_doc("Razorpay Settings").create_request(data)
- frappe.db.commit()
- return data
diff --git a/frappe/templates/pages/integrations/stripe_checkout.css b/frappe/templates/pages/integrations/stripe_checkout.css
deleted file mode 100644
index a42808aa7f..0000000000
--- a/frappe/templates/pages/integrations/stripe_checkout.css
+++ /dev/null
@@ -1,113 +0,0 @@
-.StripeElement {
- background-color: white;
- height: 40px;
- padding: 10px 12px;
- border-radius: 4px;
- border: 1px solid transparent;
- box-shadow: 0 1px 3px 0 #e6ebf1;
- -webkit-transition: box-shadow 150ms ease;
- transition: box-shadow 150ms ease;
-}
-
-.StripeElement--focus {
- box-shadow: 0 1px 3px 0 #cfd7df;
-}
-
-.StripeElement--invalid {
- border-color: #fa755a;
-}
-
-.StripeElement--webkit-autofill {
- background-color: #fefde5;
-}
-
-.stripe #payment-form {
- margin-top: 80px;
-}
-
-.stripe button {
- float: right;
- display: block;
- background: #5e64ff;
- color: white;
- box-shadow: 0 7px 14px 0 rgba(49, 49, 93, 0.10), 0 3px 6px 0 rgba(0, 0, 0, 0.08);
- border-radius: 4px;
- border: 0;
- margin-top: 20px;
- font-size: 15px;
- font-weight: 400;
- max-width: 40%;
- height: 40px;
- line-height: 38px;
- outline: none;
-}
-
-.stripe button:hover, .stripe button:focus {
- background: #2b33ff;
- border-color: #0711ff;
-}
-
-.stripe button:active {
- background: #5e64ff;
-}
-
-.stripe button:disabled {
- background: #515e80;
-}
-
-.stripe .group {
- background: white;
- box-shadow: 2px 7px 14px 2px rgba(49, 49, 93, 0.10), 0 3px 6px 0 rgba(0, 0, 0, 0.08);
- border-radius: 4px;
- margin-bottom: 20px;
-}
-
-.stripe label {
- position: relative;
- color: #8898AA;
- font-weight: 300;
- height: 40px;
- line-height: 40px;
- margin-left: 20px;
- display: block;
-}
-
-.stripe .group label:not(:last-child) {
- border-bottom: 1px solid #F0F5FA;
-}
-
-.stripe label>span {
- width: 20%;
- text-align: right;
- float: left;
-}
-
-.current-card {
- margin-left: 20px;
-}
-
-.field {
- background: transparent;
- font-weight: 300;
- border: 0;
- color: #31325F;
- outline: none;
- padding-right: 10px;
- padding-left: 10px;
- cursor: text;
- width: 70%;
- height: 40px;
- float: right;
-}
-
-.field::-webkit-input-placeholder {
- color: #CFD7E0;
-}
-
-.field::-moz-placeholder {
- color: #CFD7E0;
-}
-
-.field:-ms-input-placeholder {
- color: #CFD7E0;
-}
diff --git a/frappe/templates/pages/integrations/stripe_checkout.html b/frappe/templates/pages/integrations/stripe_checkout.html
deleted file mode 100644
index ec3d9783c5..0000000000
--- a/frappe/templates/pages/integrations/stripe_checkout.html
+++ /dev/null
@@ -1,58 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block title %} Payment {% endblock %}
-
-{%- block header -%}
-{% endblock %}
-
-{% block script %}
-
-
-{% endblock %}
-
-{%- block page_content -%}
-
-
-
- {% if image %}
-

- {% endif %}
-
{{description}}
-
-
-
-
-
-{% endblock %}
diff --git a/frappe/templates/pages/integrations/stripe_checkout.py b/frappe/templates/pages/integrations/stripe_checkout.py
deleted file mode 100644
index 1c0e20c631..0000000000
--- a/frappe/templates/pages/integrations/stripe_checkout.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
-# License: MIT. See LICENSE
-import json
-
-import frappe
-from frappe import _
-from frappe.integrations.doctype.stripe_settings.stripe_settings import get_gateway_controller
-from frappe.utils import cint, fmt_money
-
-no_cache = 1
-
-expected_keys = (
- "amount",
- "title",
- "description",
- "reference_doctype",
- "reference_docname",
- "payer_name",
- "payer_email",
- "order_id",
- "currency",
-)
-
-
-def get_context(context):
- context.no_cache = 1
-
- # all these keys exist in form_dict
- 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)
- context.publishable_key = get_api_key(context.reference_docname, gateway_controller)
- context.image = get_header_image(context.reference_docname, gateway_controller)
-
- context["amount"] = fmt_money(amount=context["amount"], currency=context["currency"])
-
- if is_a_subscription(context.reference_doctype, context.reference_docname):
- payment_plan = frappe.db.get_value(
- context.reference_doctype, context.reference_docname, "payment_plan"
- )
- recurrence = frappe.db.get_value("Payment Plan", payment_plan, "recurrence")
-
- context["amount"] = context["amount"] + " " + _(recurrence)
-
- else:
- frappe.redirect_to_message(
- _("Some information is missing"),
- _("Looks like someone sent you to an incomplete URL. Please ask them to look into it."),
- )
- frappe.local.flags.redirect_location = frappe.local.response.location
- raise frappe.Redirect
-
-
-def get_api_key(doc, gateway_controller):
- publishable_key = frappe.db.get_value("Stripe Settings", gateway_controller, "publishable_key")
- if cint(frappe.form_dict.get("use_sandbox")):
- publishable_key = frappe.conf.sandbox_publishable_key
-
- return publishable_key
-
-
-def get_header_image(doc, gateway_controller):
- header_image = frappe.db.get_value("Stripe Settings", gateway_controller, "header_img")
-
- return header_image
-
-
-@frappe.whitelist(allow_guest=True)
-def make_payment(stripe_token_id, data, reference_doctype=None, reference_docname=None):
- data = json.loads(data)
-
- data.update({"stripe_token_id": stripe_token_id})
-
- gateway_controller = get_gateway_controller(reference_doctype, reference_docname)
-
- if is_a_subscription(reference_doctype, reference_docname):
- reference = frappe.get_doc(reference_doctype, reference_docname)
- data = reference.create_subscription("stripe", gateway_controller, data)
- else:
- data = frappe.get_doc("Stripe Settings", gateway_controller).create_request(data)
-
- frappe.db.commit()
- return data
-
-
-def is_a_subscription(reference_doctype, reference_docname):
- if not frappe.get_meta(reference_doctype).has_field("is_a_subscription"):
- return False
- return frappe.db.get_value(reference_doctype, reference_docname, "is_a_subscription")
diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py
index ad9f59b3cd..0eb54c7ab0 100644
--- a/frappe/tests/test_db_query.py
+++ b/frappe/tests/test_db_query.py
@@ -517,8 +517,7 @@ class TestReportview(unittest.TestCase):
data = frappe.db.get_list(
"Web Form",
filters=[["Web Form Field", "reqd", "=", 1]],
- group_by="amount_field",
- fields=["count(*) as count", "`amount_field` as name"],
+ fields=["count(*) as count"],
order_by="count desc",
limit=50,
)
diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py
index 82e1cb3510..47eae314f7 100644
--- a/frappe/utils/__init__.py
+++ b/frappe/utils/__init__.py
@@ -559,7 +559,7 @@ def is_cli() -> bool:
return invoked_from_terminal
-def update_progress_bar(txt, i, l):
+def update_progress_bar(txt, i, l, absolute=False):
if os.environ.get("CI"):
if i == 0:
sys.stdout.write(txt)
@@ -581,8 +581,9 @@ def update_progress_bar(txt, i, l):
complete = int(float(i + 1) / l * col)
completion_bar = ("=" * complete).ljust(col, " ")
- percent_complete = str(int(float(i + 1) / l * 100))
- sys.stdout.write(f"\r{txt}: [{completion_bar}] {percent_complete}%")
+ percent_complete = f"{str(int(float(i + 1) / l * 100))}%"
+ status = f"{i} of {l}" if absolute else percent_complete
+ sys.stdout.write(f"\r{txt}: [{completion_bar}] {status}")
sys.stdout.flush()
diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py
index 8e983f11b2..6fdfba19e3 100644
--- a/frappe/utils/safe_exec.py
+++ b/frappe/utils/safe_exec.py
@@ -146,7 +146,6 @@ def get_safe_globals():
),
make_get_request=frappe.integrations.utils.make_get_request,
make_post_request=frappe.integrations.utils.make_post_request,
- get_payment_gateway_controller=frappe.integrations.utils.get_payment_gateway_controller,
socketio_port=frappe.conf.socketio_port,
get_hooks=get_hooks,
enqueue=safe_enqueue,
diff --git a/frappe/website/doctype/web_form/web_form.json b/frappe/website/doctype/web_form/web_form.json
index 0872c1d654..f9ebb3a4e7 100644
--- a/frappe/website/doctype/web_form/web_form.json
+++ b/frappe/website/doctype/web_form/web_form.json
@@ -48,17 +48,7 @@
"website_sidebar",
"scripting_style_tab",
"client_script",
- "custom_css",
- "payments_tab",
- "accept_payment",
- "payment_gateway",
- "payment_button_label",
- "payment_button_help",
- "column_break_28",
- "amount_based_on_field",
- "amount_field",
- "amount",
- "currency"
+ "custom_css"
],
"fields": [
{
@@ -233,62 +223,6 @@
"fieldtype": "Check",
"label": "Show Sidebar"
},
- {
- "default": "0",
- "fieldname": "accept_payment",
- "fieldtype": "Check",
- "label": "Accept Payment"
- },
- {
- "depends_on": "accept_payment",
- "fieldname": "payment_gateway",
- "fieldtype": "Link",
- "label": "Payment Gateway",
- "options": "Payment Gateway"
- },
- {
- "default": "Buy Now",
- "depends_on": "accept_payment",
- "fieldname": "payment_button_label",
- "fieldtype": "Data",
- "label": "Button Label"
- },
- {
- "depends_on": "accept_payment",
- "fieldname": "payment_button_help",
- "fieldtype": "Text",
- "label": "Button Help"
- },
- {
- "fieldname": "column_break_28",
- "fieldtype": "Column Break"
- },
- {
- "default": "0",
- "depends_on": "accept_payment",
- "fieldname": "amount_based_on_field",
- "fieldtype": "Check",
- "label": "Amount Based On Field"
- },
- {
- "depends_on": "eval:doc.accept_payment && doc.amount_based_on_field",
- "fieldname": "amount_field",
- "fieldtype": "Select",
- "label": "Amount Field"
- },
- {
- "depends_on": "eval:doc.accept_payment && !doc.amount_based_on_field",
- "fieldname": "amount",
- "fieldtype": "Currency",
- "label": "Amount"
- },
- {
- "depends_on": "accept_payment",
- "fieldname": "currency",
- "fieldtype": "Link",
- "label": "Currency",
- "options": "Currency"
- },
{
"description": "List as [{\"label\": _(\"Jobs\"), \"route\":\"jobs\"}]",
"fieldname": "breadcrumbs",
@@ -385,20 +319,13 @@
"fieldname": "scripting_style_tab",
"fieldtype": "Tab Break",
"label": "Scripting / Style"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "accept_payment",
- "fieldname": "payments_tab",
- "fieldtype": "Tab Break",
- "label": "Payments"
}
],
"has_web_view": 1,
"icon": "icon-edit",
"is_published_field": "published",
"links": [],
- "modified": "2022-07-18 15:51:15.288860",
+ "modified": "2022-07-24 20:29:23.059834",
"modified_by": "Administrator",
"module": "Website",
"name": "Web Form",
diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py
index e1c9e798e5..95f58e12fd 100644
--- a/frappe/website/doctype/web_form/web_form.py
+++ b/frappe/website/doctype/web_form/web_form.py
@@ -10,7 +10,6 @@ from frappe.core.api.file import get_max_file_size
from frappe.core.doctype.file import remove_file_by_url
from frappe.custom.doctype.customize_form.customize_form import docfield_properties
from frappe.desk.form.meta import get_code_files_via_hooks
-from frappe.integrations.utils import get_payment_gateway_controller
from frappe.modules.utils import export_module_json, get_doc_module
from frappe.rate_limiter import rate_limit
from frappe.utils import cstr, dict_with_keys, strip_html
@@ -50,9 +49,6 @@ class WebForm(WebsiteGenerator):
if not frappe.flags.in_import:
self.validate_fields()
- if self.accept_payment:
- self.validate_payment_amount()
-
def validate_fields(self):
"""Validate all fields are present"""
from frappe.model import no_value_fields
@@ -66,12 +62,6 @@ class WebForm(WebsiteGenerator):
if missing:
frappe.throw(_("Following fields are missing:") + "
" + "
".join(missing))
- def validate_payment_amount(self):
- if self.amount_based_on_field and not self.amount_field:
- frappe.throw(_("Please select a Amount Field."))
- elif not self.amount_based_on_field and not self.amount > 0:
- frappe.throw(_("Amount must be greater than 0."))
-
def reset_field_parent(self):
"""Convert link fields to select with names as options"""
for df in self.web_form_fields:
@@ -320,36 +310,6 @@ def get_context(context):
context.reference_doc = json.loads(context.reference_doc.as_json())
- def get_payment_gateway_url(self, doc):
- if self.accept_payment:
- controller = get_payment_gateway_controller(self.payment_gateway)
-
- title = f"Payment for {doc.doctype} {doc.name}"
- amount = self.amount
- if self.amount_based_on_field:
- amount = doc.get(self.amount_field)
-
- from decimal import Decimal
-
- if amount is None or Decimal(amount) <= 0:
- return frappe.utils.get_url(self.success_url or self.route)
-
- payment_details = {
- "amount": amount,
- "title": title,
- "description": title,
- "reference_doctype": doc.doctype,
- "reference_docname": doc.name,
- "payer_email": frappe.session.user,
- "payer_name": frappe.utils.get_fullname(frappe.session.user),
- "order_id": doc.name,
- "currency": self.currency,
- "redirect_to": frappe.utils.get_url(self.success_url or self.route),
- }
-
- # Redirect the user to this url
- return controller.get_payment_url(**payment_details)
-
def add_custom_context_and_script(self, context):
"""Update context from module if standard and append script"""
if self.web_form_module:
@@ -494,10 +454,9 @@ def get_context(context):
@frappe.whitelist(allow_guest=True)
@rate_limit(key="web_form", limit=5, seconds=60, methods=["POST"])
-def accept(web_form, data, docname=None, for_payment=False):
+def accept(web_form, data, docname=None):
"""Save the web form"""
data = frappe._dict(json.loads(data))
- for_payment = frappe.parse_json(for_payment)
files = []
files_to_delete = []
@@ -535,10 +494,6 @@ def accept(web_form, data, docname=None, for_payment=False):
doc.set(fieldname, value)
- if for_payment:
- web_form.validate_mandatory(doc)
- doc.run_method("validate_payment")
-
if doc.name:
if web_form.has_web_form_permission(doc.doctype, doc.name, "write"):
doc.save(ignore_permissions=True)
@@ -589,11 +544,7 @@ def accept(web_form, data, docname=None, for_payment=False):
remove_file_by_url(f, doctype=doc.doctype, name=doc.name)
frappe.flags.web_form_doc = doc
-
- if for_payment:
- return web_form.get_payment_gateway_url(doc)
- else:
- return doc
+ return doc
@frappe.whitelist()
diff --git a/frappe/website/web_form/request_data/request_data.json b/frappe/website/web_form/request_data/request_data.json
index c52a2f6203..e895ec9ff4 100644
--- a/frappe/website/web_form/request_data/request_data.json
+++ b/frappe/website/web_form/request_data/request_data.json
@@ -1,19 +1,15 @@
{
- "accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 0,
"allow_incomplete": 0,
"allow_multiple": 0,
"allow_print": 0,
- "amount": 0.0,
- "amount_based_on_field": 0,
"apply_document_permissions": 0,
"breadcrumbs": "",
"button_label": "Request Data",
"client_script": "",
"creation": "2019-01-24 16:19:26.886096",
- "currency": "INR",
"doc_type": "Personal Data Download Request",
"docstatus": 0,
"doctype": "Web Form",
@@ -29,7 +25,6 @@
"module": "Website",
"name": "request-data",
"owner": "Administrator",
- "payment_button_label": "Buy Now",
"published": 1,
"route": "request-data",
"route_to_success_link": 1,
diff --git a/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json b/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json
index ce11666a34..b3bf7d6b42 100644
--- a/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json
+++ b/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json
@@ -1,19 +1,15 @@
{
- "accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 0,
"allow_incomplete": 0,
"allow_multiple": 0,
"allow_print": 0,
- "amount": 0.0,
- "amount_based_on_field": 0,
"apply_document_permissions": 0,
"breadcrumbs": "",
"button_label": "Submit",
"client_script": "",
"creation": "2019-01-25 14:24:12.588810",
- "currency": "INR",
"custom_css": "[data-doctype=\"Web Form\"] {\n width: 50%;\n margin: 6rem auto;\n}",
"doc_type": "Personal Data Deletion Request",
"docstatus": 0,
@@ -30,7 +26,6 @@
"module": "Website",
"name": "request-to-delete-data",
"owner": "Administrator",
- "payment_button_label": "Buy Now",
"published": 1,
"route": "request-for-account-deletion",
"route_to_success_link": 0,
diff --git a/pyproject.toml b/pyproject.toml
index 2d9027309d..3c47edc440 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -75,16 +75,12 @@ dependencies = [
# integration dependencies
"boto3~=1.17.53",
- "braintree~=4.8.0",
"dropbox~=11.7.0",
"google-api-python-client~=2.2.0",
"google-auth-httplib2~=0.1.0",
"google-auth-oauthlib~=0.4.4",
"google-auth~=1.29.0",
"googlemaps~=4.4.5",
- "paytmchecksum~=1.7.0",
- "razorpay~=1.2.0",
- "stripe~=2.56.0",
]
[build-system]