Skip to content

Commit

Permalink
feat: improve processing hook api
Browse files Browse the repository at this point in the history
  • Loading branch information
blaggacao committed Jul 7, 2024
1 parent e5a9d14 commit 1c35421
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 26 deletions.
35 changes: 25 additions & 10 deletions payments/controllers/payment_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,12 @@ def __process_response(
}

changed = False
is_success = self.flags.status_changed_to in self.flowstates.success
is_pre_authorized = self.flags.status_changed_to in self.flowstates.pre_authorized
is_processing = self.flags.status_changed_to in self.flowstates.processing
is_declined = self.flags.status_changed_to in self.flowstates.declined

if self.flags.status_changed_to in self.flowstates.success:
if is_success:
changed = "Paid" != psl.status
psl.db_set("decline_reason", None)
psl.set_processing_payload(response, "Paid") # commits
Expand All @@ -337,7 +341,7 @@ def __process_response(
action=dict(href="/", label=_("Go to Homepage")),
**ret,
)
elif self.flags.status_changed_to in self.flowstates.pre_authorized:
elif is_pre_authorized:
changed = "Authorized" != psl.status
psl.db_set("decline_reason", None)
psl.set_processing_payload(response, "Authorized") # commits
Expand All @@ -347,7 +351,7 @@ def __process_response(
action=dict(href="/", label=_("Go to Homepage")),
**ret,
)
elif self.flags.status_changed_to in self.flowstates.processing:
elif is_processing:
changed = "Processing" != psl.status
psl.db_set("decline_reason", None)
psl.set_processing_payload(response, "Processing") # commits
Expand All @@ -357,7 +361,7 @@ def __process_response(
action=dict(href="/", label=_("Refresh")),
**ret,
)
elif self.flags.status_changed_to in self.flowstates.declined:
elif is_declined:
changed = "Declined" != psl.status
psl.db_set(
{
Expand Down Expand Up @@ -400,17 +404,28 @@ def __process_response(

try:
ref_doc.flags.payment_session = frappe._dict(
changed=changed, state=self.state, flags=self.flags, flowstates=self.flowstates
changed=changed,
is_success=is_success,
is_pre_authorized=is_pre_authorized,
is_processing=is_processing,
is_declined=is_declined,
state=self.state,
psl=psl,
) # when run as server script: can only set flags
res = ref_doc.run_method(
hookmethod,
changed,
self.state,
self.flags,
self.flowstates,
status=frappe._dict(
changed=changed,
is_success=is_success,
is_pre_authorized=is_pre_authorized,
is_processing=is_processing,
is_declined=is_declined,
),
state=self.state,
psl=psl,
)
# result from server script run
res = ref_doc.flags.payment_result or res
res = ref_doc.flags.payment_session.result or res
if res:
# type check the result value on user implementations
res["action"] = ActionAfterProcessed(**res.get("action", {})).__dict__
Expand Down
4 changes: 4 additions & 0 deletions payments/patches.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pre_model_sync]
[post_model_sync]
execute:import payments.utils.utils; payments.utils.utils.make_custom_fields()
payments.patches.add_gateway_to_buttons
25 changes: 25 additions & 0 deletions payments/patches/add_gateway_to_buttons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import click
import frappe


def execute():
for button in frappe.get_all(
"Payment Button", fields=["name", "gateway_settings", "gateway_controller"]
):
gateways = frappe.get_all(
"Payment Gateway",
{
"gateway_settings": button.gateway_settings,
"gateway_controller": button.gateway_controller,
},
pluck="name",
)
if len(gateways) > 1:
click.secho(
f"{button} was not migrated: no unabiguous matching gateway found. Set gateway manually",
color="yellow",
)
continue
button = frappe.get_doc("Payment Button", button.name)
button.payment_gateway = gateways[0]
button.save()
22 changes: 15 additions & 7 deletions payments/payments/doctype/payment_button/payment_button.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"payment_gateway",
"gateway_settings",
"gateway_controller",
"implementation_variant",
Expand All @@ -23,18 +24,18 @@
],
"fields": [
{
"fetch_from": "payment_gateway.gateway_settings",
"fieldname": "gateway_settings",
"fieldtype": "Link",
"fieldtype": "Data",
"label": "Gateway Settings",
"options": "DocType",
"reqd": 1
"read_only": 1
},
{
"fetch_from": "payment_gateway.gateway_controller",
"fieldname": "gateway_controller",
"fieldtype": "Dynamic Link",
"fieldtype": "Data",
"label": "Gateway Controller",
"options": "gateway_settings",
"reqd": 1
"read_only": 1
},
{
"depends_on": "eval: doc.implementation_variant == \"Third Party Widget\"",
Expand Down Expand Up @@ -125,11 +126,18 @@
"label": "Data Capture",
"mandatory_depends_on": "eval: doc.enabled && doc.implementation_variant == \"Data Capture\"",
"options": "HTML"
},
{
"fieldname": "payment_gateway",
"fieldtype": "Link",
"label": "Payment Gateway",
"options": "Payment Gateway",
"reqd": 1
}
],
"image_field": "icon",
"links": [],
"modified": "2024-06-17 15:09:04.579657",
"modified": "2024-07-07 11:59:22.360602",
"modified_by": "Administrator",
"module": "Payments",
"name": "Payment Button",
Expand Down
5 changes: 3 additions & 2 deletions payments/payments/doctype/payment_button/payment_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ class PaymentButton(Document):
data_capture: DF.Code | None
enabled: DF.Check
extra_payload: DF.Code | None
gateway_controller: DF.DynamicLink
gateway_controller: DF.Data | None
gateway_css: DF.Code | None
gateway_js: DF.Code | None
gateway_settings: DF.Link
gateway_settings: DF.Data | None
gateway_wrapper: DF.Code | None
icon: DF.AttachImage | None
implementation_variant: DF.Literal["Third Party Widget", "Data Capture"]
label: DF.Data
payment_gateway: DF.Link
# end: auto-generated types

# Frontend Assets (widget)
Expand Down
20 changes: 19 additions & 1 deletion payments/payments/doctype/payment_gateway/payment_gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@

frappe.ui.form.on('Payment Gateway', {
refresh: function(frm) {
},
validate_company: (frm) => {
if (!frm.doc.company) {
frappe.throw({ message: __("Please select a Company first."), title: __("Mandatory") });
}
},
setup: function(frm) {
frm.set_query("payment_account", function () {
frm.events.validate_company(frm);

}
var account_types = ["Bank", "Cash"];
return {
filters: {
account_type: ["in", account_types],
is_group: 0,
company: frm.doc.company,
},
};
});
},
});
16 changes: 14 additions & 2 deletions payments/payments/doctype/payment_gateway/payment_gateway.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"field_order": [
"gateway",
"gateway_settings",
"gateway_controller"
"gateway_controller",
"column_break_bkjg",
"company"
],
"fields": [
{
Expand All @@ -30,10 +32,20 @@
"fieldtype": "Dynamic Link",
"label": "Gateway Controller",
"options": "gateway_settings"
},
{
"fieldname": "column_break_bkjg",
"fieldtype": "Column Break"
},
{
"fieldname": "company",
"fieldtype": "Link",
"label": "Company",
"options": "Company"
}
],
"links": [],
"modified": "2022-07-24 21:17:03.864719",
"modified": "2024-07-07 11:40:01.056073",
"modified_by": "Administrator",
"module": "Payments",
"name": "Payment Gateway",
Expand Down
13 changes: 13 additions & 0 deletions payments/payments/doctype/payment_gateway/payment_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,17 @@


class PaymentGateway(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from frappe.types import DF

company: DF.Link | None
gateway: DF.Data
gateway_controller: DF.DynamicLink | None
gateway_settings: DF.Link | None
# end: auto-generated types
pass
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

if TYPE_CHECKING:
from payments.controllers import PaymentController
from payments.payments.doctype.payment_gateway.payment_gateway import PaymentGateway
from payments.payments.doctype.payment_button.payment_button import PaymentButton

import collections.abc
Expand Down Expand Up @@ -108,8 +109,17 @@ def load_state(self) -> PSLState:
)

def get_controller(self) -> "PaymentController":
"""For perfomance reasons, this is not implemented as a dynamic link but a json value
so that it is only fetched when absolutely necessary.
"""
Retrieves the payment controller associated with the current Payment Session Log's gateway.
This method uses a JSON-encoded gateway value instead of a dynamic link
for performance optimization. The controller is only fetched when necessary.
Returns:
PaymentController: The cached document of the payment controller.
Raises:
frappe.ValidationError: If no gateway is selected for this Payment Session Log.
"""
if not self.gateway:
self.log_error("No gateway selected yet")
Expand All @@ -118,6 +128,25 @@ def get_controller(self) -> "PaymentController":
doctype, docname = d["gateway_settings"], d["gateway_controller"]
return frappe.get_cached_doc(doctype, docname)

def get_gateway(self) -> "PaymentGateway":
"""
Retrieves the Payment Gateway document associated with the current Payment Session Log.
The 'gateway' attribute of the Payment Session Log serves a dual purpose,
acting as both a data store and a filter for recovering the Payment Gateway document.
Returns:
Payment Gateway: The most recent Payment Gateway document matching the stored gateway data.
Raises:
frappe.ValidationError: If no gateway is selected for this Payment Session Log.
"""
if not self.gateway:
self.log_error("No gateway selected yet")
frappe.throw(_("No gateway selected for this payment session"))
d = json.loads(self.gateway)
return frappe.get_cached_doc("Payment Gateway", d["payment_gateway"])

def get_button(self) -> "PaymentButton":
if not self.button:
self.log_error("No button selected yet")
Expand Down Expand Up @@ -157,6 +186,7 @@ def select_button(pslName: str = None, buttonName: str = None) -> str:
{
"gateway_settings": btn.gateway_settings,
"gateway_controller": btn.gateway_controller,
"payment_gateway": btn.payment_gateway,
}
),
}
Expand Down
18 changes: 16 additions & 2 deletions payments/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,16 @@ def make_custom_fields():
"insert_after": "payment_url",
}
],
"Payment Gateway": [
{
"fieldname": "payment_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Payment Account",
"options": "Account",
"insert_after": "company",
}
],
}

create_custom_fields(custom_fields)
Expand All @@ -200,10 +210,14 @@ def delete_custom_fields():
for fieldname in fieldnames:
frappe.db.delete("Custom Field", {"name": "Web Form-" + fieldname})

frappe.db.delete("Custom Field", {"name": "Payment Request-payment_session_log"})

frappe.clear_cache(doctype="Web Form")

if "erpnext" in frappe.get_installed_apps():
if frappe.get_meta("Payment Request").has_field("payment_session_log"):
frappe.db.delete("Custom Field", {"name": "Payment Request-payment_session_log"})
if frappe.get_meta("Payment Gateway").has_field("payment_account"):
frappe.db.delete("Custom Field", {"name": "Payment Gateway-payment_account"})


def before_install():
# TODO: remove this
Expand Down

0 comments on commit 1c35421

Please sign in to comment.