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: -
For details on how to get your API credentials, follow this link: https://developer.paypal.com/docs/classic/api/apiCredentials/
- -""" - -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