From ff904eb29bc28f2ff07f286b5d9aa71fa58bbf07 Mon Sep 17 00:00:00 2001 From: mrPauwHaan <120259765+mrPauwHaan@users.noreply.github.com> Date: Sat, 25 Nov 2023 10:01:32 +0100 Subject: [PATCH 001/284] Create __init__.py --- payments/payment_gateways/doctype/mollie_settings/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 payments/payment_gateways/doctype/mollie_settings/__init__.py diff --git a/payments/payment_gateways/doctype/mollie_settings/__init__.py b/payments/payment_gateways/doctype/mollie_settings/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/payments/payment_gateways/doctype/mollie_settings/__init__.py @@ -0,0 +1 @@ + From abf45dc3dde343a8f26d6cc93b3ddc0180934a14 Mon Sep 17 00:00:00 2001 From: mrPauwHaan <120259765+mrPauwHaan@users.noreply.github.com> Date: Sat, 25 Nov 2023 10:01:53 +0100 Subject: [PATCH 002/284] Create mollie_settings.js --- .../doctype/mollie_settings/mollie_settings.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 payments/payment_gateways/doctype/mollie_settings/mollie_settings.js diff --git a/payments/payment_gateways/doctype/mollie_settings/mollie_settings.js b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.js new file mode 100644 index 00000000..bb0899af --- /dev/null +++ b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.js @@ -0,0 +1,5 @@ +frappe.ui.form.on('Mollie Settings', { + refresh: function(frm) { + + } +}); From 8d18b137c4bd7b9b75c19270b8df9994513a427a Mon Sep 17 00:00:00 2001 From: mrPauwHaan <120259765+mrPauwHaan@users.noreply.github.com> Date: Sat, 25 Nov 2023 10:02:12 +0100 Subject: [PATCH 003/284] Create mollie_settings.json --- .../mollie_settings/mollie_settings.json | 315 ++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 payments/payment_gateways/doctype/mollie_settings/mollie_settings.json diff --git a/payments/payment_gateways/doctype/mollie_settings/mollie_settings.json b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.json new file mode 100644 index 00000000..a6aa35eb --- /dev/null +++ b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.json @@ -0,0 +1,315 @@ +{ + "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": "2023-11-25 13:32:14.429916", + "modified_by": "Administrator", + "module": "Payment Gateways", + "name": "Mollie 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 + } From 8ab742a7faac526fe5797c9509e83de24bb390ce Mon Sep 17 00:00:00 2001 From: mrPauwHaan <120259765+mrPauwHaan@users.noreply.github.com> Date: Sat, 25 Nov 2023 10:02:29 +0100 Subject: [PATCH 004/284] Create mollie_settings.py --- .../mollie_settings/mollie_settings.py | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 payments/payment_gateways/doctype/mollie_settings/mollie_settings.py diff --git a/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py new file mode 100644 index 00000000..187a0ec4 --- /dev/null +++ b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py @@ -0,0 +1,165 @@ +from urllib.parse import urlencode + +import frappe +from frappe import _ +from frappe.integrations.utils import create_request_log, make_get_request +from frappe.model.document import Document +from frappe.utils import call_hook_method, cint, flt, get_url +from payments.utils import create_payment_gateway + + +class MollieSettings(Document): + supported_currencies = [ + "AED", + "AUD", + "BGN", + "BRL", + "CAD", + "CHF", + "CZK", + "DKK", + "EUR", + "GBP", + "HKD", + "HUF", + "ILS", + "ISK", + "JPY", + "MXN", + "MYR", + "NOK", + "NZD", + "PHP", + "PLN", + "RON", + "RUB", + "SEK", + "SGD", + "THB", + "TWD", + "USD", + "ZAR", + ] + + def on_update(self): + create_payment_gateway( + "Mollie-" + self.gateway_name, + settings="Mollie Settings", + controller=self.gateway_name, + ) + call_hook_method("payment_gateway_enabled", gateway="Mollie-" + self.gateway_name) + if not self.flags.ignore_mandatory: + self.validate_mollie_credentials() + + def validate_mollie_credentials(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.mollie.com/v2/payments", 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. Mollie does not support transactions in currency '{0}'" + ).format(currency) + ) + + def get_payment_url(self, **kwargs): + return get_url(f"./mollie_checkout?{urlencode(kwargs)}") + + def create_request(self, data): + import mollie + + self.data = frappe._dict(data) + mollie.api_key = self.get_password(fieldname="secret_key", raise_exception=False) + mollie.default_http_client = mollie.http_client.RequestsClient() + + try: + self.integration_request = create_request_log(self.data, service_name="Mollie") + return self.create_charge_on_mollie() + + 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 Mollie configuration. In case of failure, the amount will get refunded to your account." + ), + ), + "status": 401, + } + + def create_charge_on_mollie(self): + import mollie + + try: + charge = mollie.Charge.create( + amount=cint(flt(self.data.amount) * 100), + currency=self.data.currency, + source=self.data.mollie_token_id, + description=self.data.description, + billingEmail=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, "Mollie 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?doctype={}&docname={}".format( + self.data.reference_doctype, self.data.reference_docname + ) + + 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 From 7aabbe6a2892ee244080badb9801f3af9a9ae48c Mon Sep 17 00:00:00 2001 From: mrPauwHaan <120259765+mrPauwHaan@users.noreply.github.com> Date: Sat, 25 Nov 2023 11:38:38 +0100 Subject: [PATCH 005/284] Update mollie_settings.py --- .../payment_gateways/doctype/mollie_settings/mollie_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py index 187a0ec4..7091db55 100644 --- a/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py +++ b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py @@ -72,7 +72,7 @@ def validate_transaction_currency(self, currency): ) def get_payment_url(self, **kwargs): - return get_url(f"./mollie_checkout?{urlencode(kwargs)}") + return get_url(f"https://api.mollie.com/v2/payment-links/?{urlencode(kwargs)}") def create_request(self, data): import mollie From 9b919602161fa04e614c444b8f9fae701eb92eea Mon Sep 17 00:00:00 2001 From: mrPauwHaan <120259765+mrPauwHaan@users.noreply.github.com> Date: Sat, 25 Nov 2023 13:47:14 +0100 Subject: [PATCH 006/284] Update mollie_settings.py --- .../mollie_settings/mollie_settings.py | 562 ++++++++++++++---- 1 file changed, 455 insertions(+), 107 deletions(-) diff --git a/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py index 7091db55..04943a5c 100644 --- a/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py +++ b/payments/payment_gateways/doctype/mollie_settings/mollie_settings.py @@ -1,165 +1,513 @@ +# Copyright (c) 2015, Frappe Technologies and contributors +# License: MIT. See LICENSE + +""" +# Integrating PayPal + +### 1. Validate Currency Support + +Example: + + from payments.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: +