diff --git a/payments/hooks.py b/payments/hooks.py index c6039c77..3cc79b3a 100644 --- a/payments/hooks.py +++ b/payments/hooks.py @@ -29,7 +29,7 @@ # page_js = {"page" : "public/js/file.js"} # include js in doctype views -# doctype_js = {"doctype" : "public/js/doctype.js"} +doctype_js = {"Web Form": "public/js/web_form.js"} # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} diff --git a/payments/overrides/payment_webform.py b/payments/overrides/payment_webform.py index 1b62e413..09ec50a1 100644 --- a/payments/overrides/payment_webform.py +++ b/payments/overrides/payment_webform.py @@ -27,6 +27,8 @@ def get_payment_gateway_url(self, doc): controller = get_payment_gateway_controller(self.payment_gateway) title = f"Payment for {doc.doctype} {doc.name}" + + # Set Amount amount = self.amount if self.amount_based_on_field: amount = doc.get(self.amount_field) @@ -36,14 +38,25 @@ def get_payment_gateway_url(self, doc): if amount is None or Decimal(amount) <= 0: return frappe.utils.get_url(self.success_url or self.route) + # Set Payer Name + payer_name = frappe.utils.get_fullname(frappe.session.user) + if self.payer_name_based_on_field: + payer_name = doc.get(self.payer_name_field) + + # Set Payer Email + payer_email = frappe.session.user + if self.payer_email_based_on_field: + payer_email = doc.get(self.payer_email_field) + payment_details = { "amount": amount, "title": title, "description": title, "reference_doctype": doc.doctype, "reference_docname": doc.name, - "payer_email": frappe.session.user, - "payer_name": frappe.utils.get_fullname(frappe.session.user), + "payment_gateway": self.payment_gateway, + "payer_email": payer_email, + "payer_name": payer_name, "order_id": doc.name, "currency": self.currency, "redirect_to": frappe.utils.get_url(self.success_url or self.route), @@ -101,6 +114,8 @@ def accept(web_form, data, docname=None, for_payment=False): if for_payment: web_form.validate_mandatory(doc) doc.run_method("validate_payment") + # set payment gateway + doc.set("payment_gateway", web_form.payment_gateway) if doc.name: if web_form.has_web_form_permission(doc.doctype, doc.name, "write"): diff --git a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py index 29dff12b..7e8c5f46 100644 --- a/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py +++ b/payments/payment_gateways/doctype/stripe_settings/stripe_settings.py @@ -191,7 +191,7 @@ def validate_minimum_transaction_amount(self, currency, amount): ) def get_payment_url(self, **kwargs): - return get_url(f"./stripe_checkout?{urlencode(kwargs)}") + return f"/stripe_checkout?{urlencode(kwargs)}" def create_request(self, data): import stripe @@ -244,12 +244,13 @@ 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 + custom_redirect_to_override = None 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( + custom_redirect_to, custom_redirect_to_override = frappe.get_doc( self.data.reference_doctype, self.data.reference_docname ).run_method("on_payment_authorized", self.flags.status_changed_to) except Exception: @@ -273,6 +274,8 @@ def finalize_request(self): if redirect_message: redirect_url += "&" + urlencode({"redirect_message": redirect_message}) + if custom_redirect_to_override: + redirect_url = redirect_to return {"redirect_to": redirect_url, "status": status} diff --git a/payments/payments/custom/web_form.json b/payments/payments/custom/web_form.json new file mode 100644 index 00000000..bf0aeaa1 --- /dev/null +++ b/payments/payments/custom/web_form.json @@ -0,0 +1,120 @@ +{ + "custom_fields": [ + { + "dt": "Web Form", + "fieldname": "payments_tab", + "fieldtype": "Tab Break", + "label": "Payments", + "insert_after": "custom_css", + "is_system_generated": 1 + }, + { + "default": "0", + "dt": "Web Form", + "fieldname": "accept_payment", + "fieldtype": "Check", + "label": "Accept Payments", + "insert_after": "payments_tab", + "is_system_generated": 1 + }, + { + "depends_on": "accept_payment", + "dt": "Web Form", + "fieldname": "payments_sb", + "fieldtype": "Section Break", + "insert_after": "accept_payment", + "is_system_generated": 1 + }, + { + "depends_on": "eval:!doc.amount_based_on_field", + "dt": "Web Form", + "fieldname": "amount", + "fieldtype": "Currency", + "label": "Amount", + "insert_after": "payments_sb", + "is_system_generated": 1 + }, + { + "dt": "Web Form", + "fieldname": "currency", + "fieldtype": "Link", + "label": "Currency", + "options": "Currency", + "insert_after": "amount", + "is_system_generated": 1 + }, + { + "dt": "Web Form", + "fieldname": "payment_gateway", + "fieldtype": "Link", + "label": "Payment Gateway", + "options": "Payment Gateway", + "insert_after": "currency", + "is_system_generated": 1 + }, + { + "dt": "Web Form", + "fieldname": "payments_cb", + "fieldtype": "Column Break", + "insert_after": "payment_gateway", + "is_system_generated": 1 + }, + { + "default": "0", + "dt": "Web Form", + "fieldname": "amount_based_on_field", + "fieldtype": "Check", + "label": "Amount Based On Field", + "insert_after": "payments_cb", + "is_system_generated": 1 + }, + { + "depends_on": "eval:doc.amount_based_on_field", + "dt": "Web Form", + "fieldname": "amount_field", + "fieldtype": "Select", + "label": "Amount Field", + "insert_after": "amount_based_on_field", + "is_system_generated": 1 + }, + { + "default": "0", + "dt": "Web Form", + "fieldname": "payer_name_based_on_field", + "fieldtype": "Check", + "label": "Payer Name Based On Field", + "insert_after": "amount_field", + "is_system_generated": 1 + }, + { + "depends_on": "eval:doc.payer_name_based_on_field", + "dt": "Web Form", + "fieldname": "payer_name_field", + "fieldtype": "Select", + "label": "Payer Name Field", + "insert_after": "payer_name_based_on_field", + "is_system_generated": 1 + }, + { + "default": "0", + "dt": "Web Form", + "fieldname": "payer_email_based_on_field", + "fieldtype": "Check", + "label": "Payer Email Based On Field", + "insert_after": "payer_name_field", + "is_system_generated": 1 + }, + { + "depends_on": "eval:doc.payer_email_based_on_field", + "dt": "Web Form", + "fieldname": "payer_email_field", + "fieldtype": "Select", + "label": "Payer Email Field", + "insert_after": "payer_email_based_on_field", + "is_system_generated": 1 + } + ], + "property_setters": [], + "sync_on_migrate": 1, + "doctype": "Web Form" +} \ No newline at end of file diff --git a/payments/public/js/web_form.js b/payments/public/js/web_form.js new file mode 100644 index 00000000..eb74fc60 --- /dev/null +++ b/payments/public/js/web_form.js @@ -0,0 +1,90 @@ +frappe.ui.form.on("Web Form", { + set_fields(frm) { + let doc = frm.doc; + + let update_options = (options) => { + [ + frm.fields_dict.web_form_fields.grid, + frm.fields_dict.list_columns.grid, + ].forEach((obj) => { + obj.update_docfield_property("fieldname", "options", options); + }); + }; + + if (!doc.doc_type) { + update_options([]); + frm.set_df_property("amount_field", "options", []); + frm.set_df_property("payer_name_field", "options", []); + frm.set_df_property("payer_email_field", "options", []); + return; + } + + update_options([`Fetching fields from ${doc.doc_type}...`]); + + new Promise((resolve) => + frappe.model.with_doctype(doc.doc_type, resolve) + ).then(() => { + const fields = frappe.meta.get_docfields(doc.doc_type).filter((df) => { + return ( + (frappe.model.is_value_type(df.fieldtype) && + !["lft", "rgt"].includes(df.fieldname)) || + ["Table", "Table Multiselect"].includes(df.fieldtype) || + frappe.model.layout_fields.includes(df.fieldtype) + ); + }); + + let as_select_option = (df) => ({ + label: df.label, + value: df.fieldname, + }); + + // Update main field options + update_options(fields.map(as_select_option)); + + // Amount Field Options + let currency_fields = fields + .filter((df) => ["Currency", "Float"].includes(df.fieldtype)) + .map(as_select_option); + if (!currency_fields.length) { + currency_fields = [ + { + label: `No currency fields in ${doc.doc_type}`, + value: "", + disabled: true, + }, + ]; + } + frm.set_df_property("amount_field", "options", currency_fields); + + // Payer Name Field Options + let payer_name_fields = fields + .filter((df) => ["Data", "Link"].includes(df.fieldtype)) + .map(as_select_option); + if (!payer_name_fields.length) { + payer_name_fields = [ + { + label: `No data or link fields in ${doc.doc_type}`, + value: "", + disabled: true, + }, + ]; + } + frm.set_df_property("payer_name_field", "options", payer_name_fields); + + // Payer Email Field Options + let payer_email_fields = fields + .filter((df) => ["Email"].includes(df.options)) + .map(as_select_option); + if (!payer_email_fields.length) { + payer_email_fields = [ + { + label: `No email fields in ${doc.doc_type}`, + value: "", + disabled: true, + }, + ]; + } + frm.set_df_property("payer_email_field", "options", payer_email_fields); + }); + }, +}); diff --git a/payments/utils/utils.py b/payments/utils/utils.py index 64e79a99..8a9f763c 100644 --- a/payments/utils/utils.py +++ b/payments/utils/utils.py @@ -60,88 +60,22 @@ def create_payment_gateway(gateway, settings=None, controller=None): def make_custom_fields(): - if not frappe.get_meta("Web Form").has_field("payments_tab"): - click.secho("* Installing Payment Custom Fields in Web Form") - - create_custom_fields( - { - "Web Form": [ - { - "fieldname": "payments_tab", - "fieldtype": "Tab Break", - "label": "Payments", - "insert_after": "custom_css", - }, - { - "default": "0", - "fieldname": "accept_payment", - "fieldtype": "Check", - "label": "Accept Payment", - "insert_after": "payments", - }, - { - "depends_on": "accept_payment", - "fieldname": "payment_gateway", - "fieldtype": "Link", - "label": "Payment Gateway", - "options": "Payment Gateway", - "insert_after": "accept_payment", - }, - { - "default": "Buy Now", - "depends_on": "accept_payment", - "fieldname": "payment_button_label", - "fieldtype": "Data", - "label": "Button Label", - "insert_after": "payment_gateway", - }, - { - "depends_on": "accept_payment", - "fieldname": "payment_button_help", - "fieldtype": "Text", - "label": "Button Help", - "insert_after": "payment_button_label", - }, - { - "fieldname": "payments_cb", - "fieldtype": "Column Break", - "insert_after": "payment_button_help", - }, - { - "default": "0", - "depends_on": "accept_payment", - "fieldname": "amount_based_on_field", - "fieldtype": "Check", - "label": "Amount Based On Field", - "insert_after": "payments_cb", - }, - { - "depends_on": "eval:doc.accept_payment && doc.amount_based_on_field", - "fieldname": "amount_field", - "fieldtype": "Select", - "label": "Amount Field", - "insert_after": "amount_based_on_field", - }, - { - "depends_on": "eval:doc.accept_payment && !doc.amount_based_on_field", - "fieldname": "amount", - "fieldtype": "Currency", - "label": "Amount", - "insert_after": "amount_field", - }, - { - "depends_on": "accept_payment", - "fieldname": "currency", - "fieldtype": "Link", - "label": "Currency", - "options": "Currency", - "insert_after": "amount", - }, - ] - } - ) + if "erpnext" in frappe.get_installed_apps(): + custom_fields = { + "GoCardless Mandate": [ + { + "fieldname": "customer", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Customer", + "options": "Customer", + "reqd": 1, + "insert_after": "disabled", + } + ] + } - frappe.clear_cache(doctype="Web Form") + create_custom_fields(custom_fields) if "erpnext" in frappe.get_installed_apps(): custom_fields = { @@ -173,16 +107,21 @@ def delete_custom_fields(): "fieldname": ( "in", ( - "payments_tab", "accept_payment", - "payment_gateway", - "payment_button_label", - "payment_button_help", - "payments_cb", - "amount_field", "amount_based_on_field", + "amount_field", "amount", "currency", + "payer_email_based_on_field", + "payer_email_field", + "payer_name_based_on_field", + "payer_name_field", + "payment_button_help", + "payment_button_label", + "payment_gateway", + "payments_cb", + "payments_sb", + "payments_tab", ), ), },