From 6be0b933231c74db21214d38938985547294c7b0 Mon Sep 17 00:00:00 2001 From: Saullo Bretas Silva Date: Sun, 5 Nov 2023 17:08:55 -0300 Subject: [PATCH 1/3] fix: update stripe redirect URL to include reference doctype and docname (cherry picked from commit 177de8d81a61a4022939acb6b13b205f1669663d) --- .../doctype/stripe_settings/stripe_settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py index 0547a528..32adab85 100644 --- a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py +++ b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py @@ -255,7 +255,9 @@ def finalize_request(self): if custom_redirect_to: redirect_to = custom_redirect_to - redirect_url = "payment-success" + redirect_url = "payment-success?doctype={}&docname={}".format( + self.data.reference_doctype, self.data.reference_docname + ) if self.redirect_url: redirect_url = self.redirect_url From a01684fddd48a637068986d96913b0a371b37097 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 23 Jan 2024 16:48:50 +0530 Subject: [PATCH 2/3] fix: payment sucess redirect error --- .../doctype/stripe_settings/stripe_settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py index 32adab85..816b77e9 100644 --- a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py +++ b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py @@ -265,8 +265,11 @@ def finalize_request(self): else: redirect_url = "payment-failed" - if redirect_to: + if redirect_to and "?" in redirect_url: + redirect_url += "&" + urlencode({"redirect_to": redirect_to}) + else: redirect_url += "?" + urlencode({"redirect_to": redirect_to}) + if redirect_message: redirect_url += "&" + urlencode({"redirect_message": redirect_message}) From 02780ee7c41139886ff03f30805c8fd40fdb26a8 Mon Sep 17 00:00:00 2001 From: Ramdani Date: Mon, 18 Mar 2024 09:10:39 +0700 Subject: [PATCH 3/3] add xendit integration --- payments/api.py | 59 ++++++++ .../doctype/xendit_settings/__init__.py | 0 .../xendit_settings/test_xendit_settings.py | 9 ++ .../xendit_settings/xendit_settings.js | 8 + .../xendit_settings/xendit_settings.json | 71 +++++++++ .../xendit_settings/xendit_settings.py | 96 ++++++++++++ payments/payments/doctype/__init__.py | 0 .../doctype/xendit_payment_log/__init__.py | 0 .../test_xendit_payment_log.py | 9 ++ .../xendit_payment_log/xendit_payment_log.js | 8 + .../xendit_payment_log.json | 138 ++++++++++++++++++ .../xendit_payment_log/xendit_payment_log.py | 9 ++ 12 files changed, 407 insertions(+) create mode 100644 payments/api.py create mode 100644 payments/payment_gateways/doctype/xendit_settings/__init__.py create mode 100644 payments/payment_gateways/doctype/xendit_settings/test_xendit_settings.py create mode 100644 payments/payment_gateways/doctype/xendit_settings/xendit_settings.js create mode 100644 payments/payment_gateways/doctype/xendit_settings/xendit_settings.json create mode 100644 payments/payment_gateways/doctype/xendit_settings/xendit_settings.py create mode 100644 payments/payments/doctype/__init__.py create mode 100644 payments/payments/doctype/xendit_payment_log/__init__.py create mode 100644 payments/payments/doctype/xendit_payment_log/test_xendit_payment_log.py create mode 100644 payments/payments/doctype/xendit_payment_log/xendit_payment_log.js create mode 100644 payments/payments/doctype/xendit_payment_log/xendit_payment_log.json create mode 100644 payments/payments/doctype/xendit_payment_log/xendit_payment_log.py diff --git a/payments/api.py b/payments/api.py new file mode 100644 index 00000000..811a0ae6 --- /dev/null +++ b/payments/api.py @@ -0,0 +1,59 @@ +import frappe +from frappe.utils import nowdate +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry + + +@frappe.whitelist(allow_guest=True) +def accept_payment(**data): + """ + headers: X-CALLBACK-TOKEN + data: { + "id": "65f675eec32d920fd76d8034", + "amount": 500000, + "status": "PAID", + "created": "2024-03-17T04:47:43.048Z", + "is_high": false, + "paid_at": "2024-03-17T04:48:32.000Z", + "updated": "2024-03-17T04:48:33.041Z", + "user_id": "65e0a60d213e0478ced4bb3e", + "currency": "IDR", + "bank_code": "MANDIRI", + "payment_id": "46913fa1-3351-47c2-aa55-3b0fde81ee36", + "description": "Invoice Demo #123", + "external_id": "invoice-1231241", + "paid_amount": 500000, + "payer_email": "ramdani@sopwer.net", + "merchant_name": "Sopwer", + "payment_method": "BANK_TRANSFER", + "payment_channel": "MANDIRI", + "payment_destination": "8860827838227" + } + """ + + data = frappe.parse_json(data) + payment_log = frappe.get_list("Xendit Payment Log", filters={"document": data['external_id']}, fields=["name"]) + if payment_log: + xpl = frappe.get_doc("Xendit Payment Log", payment_log[0].name) + token_verify = frappe.db.get_value("Xendit Settings", xpl.xendit_account, "token_verify") + if frappe.request.headers.get('X-Callback-Token') == token_verify: + pr = frappe.get_doc(xpl.doc_type, xpl.document) + pe = get_payment_entry(pr.reference_doctype, pr.reference_name) + # Ubah status payment entry menjadi "paid" + pe.reference_no = data['external_id'] + pe.reference_date = data['paid_at'][:10] + pe.insert(ignore_permissions=True) + pe.submit() + + # Update Xendit Payment Log + frappe.db.set_value("Xendit Payment Log", payment_log[0].name, "status", data['status']) + frappe.db.set_value("Xendit Payment Log", payment_log[0].name, "callback_payload", frappe.as_json(data)) + frappe.db.commit() + + return "Payment entry updated successfully" + else: + frappe.log_error("Request Payment {0} Is Invalid".format(data['id'])) + return "Request Payment {0} Is Invalid".format(data['id']) + + else: + frappe.log_error("Error Payment {0} Log Not Found".format(data['id'])) + return "Payment log not found" diff --git a/payments/payment_gateways/doctype/xendit_settings/__init__.py b/payments/payment_gateways/doctype/xendit_settings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/payments/payment_gateways/doctype/xendit_settings/test_xendit_settings.py b/payments/payment_gateways/doctype/xendit_settings/test_xendit_settings.py new file mode 100644 index 00000000..b85fc6b5 --- /dev/null +++ b/payments/payment_gateways/doctype/xendit_settings/test_xendit_settings.py @@ -0,0 +1,9 @@ +# Copyright (c) 2024, Frappe Technologies and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestXenditSettings(FrappeTestCase): + pass diff --git a/payments/payment_gateways/doctype/xendit_settings/xendit_settings.js b/payments/payment_gateways/doctype/xendit_settings/xendit_settings.js new file mode 100644 index 00000000..afd02b6c --- /dev/null +++ b/payments/payment_gateways/doctype/xendit_settings/xendit_settings.js @@ -0,0 +1,8 @@ +// Copyright (c) 2024, Frappe Technologies and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Xendit Settings", { +// refresh(frm) { + +// }, +// }); diff --git a/payments/payment_gateways/doctype/xendit_settings/xendit_settings.json b/payments/payment_gateways/doctype/xendit_settings/xendit_settings.json new file mode 100644 index 00000000..1f41d752 --- /dev/null +++ b/payments/payment_gateways/doctype/xendit_settings/xendit_settings.json @@ -0,0 +1,71 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "field:title", + "creation": "2024-03-17 10:23:10.932585", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "title", + "secret_api_key", + "public_key", + "token_verify", + "use_sandbox" + ], + "fields": [ + { + "fieldname": "secret_api_key", + "fieldtype": "Data", + "label": "Secret Api Key" + }, + { + "fieldname": "public_key", + "fieldtype": "Data", + "label": "Public Key" + }, + { + "fieldname": "token_verify", + "fieldtype": "Password", + "label": "Token Verify" + }, + { + "default": "0", + "fieldname": "use_sandbox", + "fieldtype": "Check", + "label": "Use Sandbox" + }, + { + "fieldname": "title", + "fieldtype": "Data", + "label": "Title", + "unique": 1 + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2024-03-17 15:58:18.062396", + "modified_by": "Administrator", + "module": "Payment Gateways", + "name": "Xendit Settings", + "naming_rule": "By fieldname", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "show_title_field_in_link": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "title_field": "title" +} \ No newline at end of file diff --git a/payments/payment_gateways/doctype/xendit_settings/xendit_settings.py b/payments/payment_gateways/doctype/xendit_settings/xendit_settings.py new file mode 100644 index 00000000..83289d47 --- /dev/null +++ b/payments/payment_gateways/doctype/xendit_settings/xendit_settings.py @@ -0,0 +1,96 @@ +# Copyright (c) 2024, Frappe Technologies and contributors +# For license information, please see license.txt + +import frappe +import json +from frappe.model.document import Document +from urllib.parse import urlencode + +import xendit +from xendit.apis import BalanceApi +from pprint import pprint +from xendit.apis import InvoiceApi +from xendit.invoice.model.create_invoice_request import CreateInvoiceRequest +from xendit.invoice.model import CustomerObject, AddressObject, NotificationPreference, NotificationChannel, InvoiceItem, InvoiceFee, ChannelProperties, ChannelPropertiesCards +from datetime import datetime +from frappe.utils import call_hook_method, cint, flt, get_url + +from payments.utils import create_payment_gateway + + +def serialize_datetime(obj): + if isinstance(obj, datetime): + return obj.strftime('%Y-%m-%d %H:%M:%S') + raise TypeError("Type not serializable") + +class XenditSettings(Document): + + supported_currencies = ["IDR"] + + def validate_transaction_currency(self, currency): + if currency not in self.supported_currencies: + frappe.throw( + _( + "Please select another payment method. Xendit does not support transactions in currency '{0}'" + ).format(currency) + ) + + def on_update(self): + create_payment_gateway( + "Xendit-" + self.title, + settings="Xendit Settings", + controller=self.title, + ) + + def get_invoice_by_id(self, invoice_id): + xendit.set_api_key(self.secret_api_key) + + api_client = xendit.ApiClient() + api_instance = InvoiceApi(api_client) + try: + # Get an invoice by ID + api_response = api_instance.get_invoice_by_id(invoice_id) + pprint(api_response) + except xendit.XenditSdkException as e: + print("Exception when calling InvoiceApi->get_invoice: %s\n" % e) + + + def create_request(self,doc_type, document, payload): + xendit.set_api_key(self.secret_api_key) + + api_client = xendit.ApiClient() + api_instance = InvoiceApi(api_client) + create_invoice_request = CreateInvoiceRequest( + **payload + ) + try: + # Create an invoice + api_response = api_instance.create_invoice(create_invoice_request) + # import pdb + # pdb.set_trace() + xpl = frappe.new_doc("Xendit Payment Log") + xpl.xendit_account = self.name + xpl.respond_payload = json.dumps(api_response.to_dict(), default=serialize_datetime, indent=4) #json.dumps(api_response.to_dict()) + xpl.doc_type = doc_type + xpl.document = document + xpl.status = api_response.status + xpl.amount = api_response.amount + xpl.checkout_url = api_response.invoice_url + xpl.submit() + frappe.db.commit() + return xpl.checkout_url + # pprint(api_response) + except xendit.XenditSdkException as e: + print("Exception when calling InvoiceApi->create_invoice: %s\n" % e) + + + def get_payment_url(self, **kwargs): + payload = {'external_id': kwargs['reference_docname'], + 'amount': kwargs['amount'], + 'payer_email': kwargs['payer_email'], + 'description':str(kwargs['description']), + 'currency': kwargs['currency'] + } + checkout_url = self.create_request("Payment Request", kwargs['reference_docname'], payload) + return get_url(checkout_url) + diff --git a/payments/payments/doctype/__init__.py b/payments/payments/doctype/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/payments/payments/doctype/xendit_payment_log/__init__.py b/payments/payments/doctype/xendit_payment_log/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/payments/payments/doctype/xendit_payment_log/test_xendit_payment_log.py b/payments/payments/doctype/xendit_payment_log/test_xendit_payment_log.py new file mode 100644 index 00000000..b127ed0a --- /dev/null +++ b/payments/payments/doctype/xendit_payment_log/test_xendit_payment_log.py @@ -0,0 +1,9 @@ +# Copyright (c) 2024, Frappe Technologies and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestXenditPaymentLog(FrappeTestCase): + pass diff --git a/payments/payments/doctype/xendit_payment_log/xendit_payment_log.js b/payments/payments/doctype/xendit_payment_log/xendit_payment_log.js new file mode 100644 index 00000000..97e9641a --- /dev/null +++ b/payments/payments/doctype/xendit_payment_log/xendit_payment_log.js @@ -0,0 +1,8 @@ +// Copyright (c) 2024, Frappe Technologies and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Xendit Payment Log", { +// refresh(frm) { + +// }, +// }); diff --git a/payments/payments/doctype/xendit_payment_log/xendit_payment_log.json b/payments/payments/doctype/xendit_payment_log/xendit_payment_log.json new file mode 100644 index 00000000..381d7f52 --- /dev/null +++ b/payments/payments/doctype/xendit_payment_log/xendit_payment_log.json @@ -0,0 +1,138 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2024-03-17 13:35:16.565892", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "section_break_kylk", + "amended_from", + "xendit_account", + "doc_type", + "document", + "amount", + "description", + "checkout_url", + "callback_payload", + "respond_payload", + "last_updated", + "paid_at", + "status" + ], + "fields": [ + { + "fieldname": "section_break_kylk", + "fieldtype": "Section Break" + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Xendit Payment Log", + "print_hide": 1, + "read_only": 1, + "search_index": 1 + }, + { + "fieldname": "xendit_account", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Xendit Account", + "options": "Xendit Settings", + "reqd": 1 + }, + { + "fieldname": "doc_type", + "fieldtype": "Link", + "in_list_view": 1, + "label": "DocType", + "options": "DocType", + "reqd": 1 + }, + { + "fieldname": "document", + "fieldtype": "Dynamic Link", + "in_list_view": 1, + "label": "Document", + "options": "doc_type", + "reqd": 1 + }, + { + "fieldname": "amount", + "fieldtype": "Currency", + "label": "Amount" + }, + { + "fieldname": "description", + "fieldtype": "Data", + "label": "Description" + }, + { + "fieldname": "last_updated", + "fieldtype": "Datetime", + "label": "Last Updated" + }, + { + "fieldname": "callback_payload", + "fieldtype": "JSON", + "label": "Callback Payload" + }, + { + "fieldname": "respond_payload", + "fieldtype": "JSON", + "label": "Respond Payload" + }, + { + "fieldname": "checkout_url", + "fieldtype": "Data", + "label": "Checkout URL", + "options": "URL" + }, + { + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "options": "PENDING\nPAID" + }, + { + "fieldname": "paid_at", + "fieldtype": "Datetime", + "label": "Paid At" + } + ], + "index_web_pages_for_search": 1, + "is_submittable": 1, + "links": [], + "modified": "2024-03-17 14:18:22.489279", + "modified_by": "Administrator", + "module": "Payments", + "name": "Xendit Payment Log", + "owner": "Administrator", + "permissions": [ + { + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "submit": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [ + { + "color": "Green", + "title": "PAID" + }, + { + "color": "Gray", + "title": "PENDING" + } + ] +} \ No newline at end of file diff --git a/payments/payments/doctype/xendit_payment_log/xendit_payment_log.py b/payments/payments/doctype/xendit_payment_log/xendit_payment_log.py new file mode 100644 index 00000000..5d9d8717 --- /dev/null +++ b/payments/payments/doctype/xendit_payment_log/xendit_payment_log.py @@ -0,0 +1,9 @@ +# Copyright (c) 2024, Frappe Technologies and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class XenditPaymentLog(Document): + pass