From bddbb355418f29809a96c66ac56928582940ea27 Mon Sep 17 00:00:00 2001 From: Ty Reynolds Date: Thu, 19 Mar 2026 08:24:28 -0400 Subject: [PATCH] Sign up customer for autopay? feature when manual payment is ran. Version 1 --- ns_app/api/payments.py | 53 +++++++++++++++++++++++++++++++ ns_app/public/js/sales_invoice.js | 42 ++++++++++++++++++++---- 2 files changed, 88 insertions(+), 7 deletions(-) diff --git a/ns_app/api/payments.py b/ns_app/api/payments.py index 020233a..4113c93 100644 --- a/ns_app/api/payments.py +++ b/ns_app/api/payments.py @@ -158,6 +158,59 @@ def run_token_payment(invoice, token): return {"success": True} return {"success": False, "error": result.get("responsetext", ["Error"])[0]} + + +@frappe.whitelist() +def save_to_autopay(customer, token): + import requests + import urllib.parse + + inv_customer = frappe.get_doc("Customer", customer) + + customer_name = (inv_customer.customer_name or "Customer").strip() + + if " " in customer_name: + first_name, last_name = customer_name.split(" ", 1) + else: + first_name = customer_name + last_name = "." + + data = { + "security_key": frappe.conf.get("nmi_security_key"), + "type": "add_customer", + "payment_token": token, + + "first_name": first_name, + "last_name": last_name, + "customer_vault": "add_customer" + } + + try: + response = requests.post( + "https://secure.nmi.com/api/transact.php", + data=data, + timeout=30 + ) + + result = urllib.parse.parse_qs(response.text) + + success = result.get("response", ["0"])[0] + vault_id = result.get("customer_vault_id", [""])[0] + message = result.get("responsetext", ["Failed"])[0] + + except Exception: + frappe.log_error(frappe.get_traceback(), "NMI Vault Error") + return {"success": False, "error": "Vault request failed"} + + if success == "1" and vault_id: + # Save to customer + inv_customer.custom_auto_pay_id = vault_id + inv_customer.custom_auto_pay_status = 1 + inv_customer.save(ignore_permissions=True) + + return {"success": True} + + return {"success": False, "error": message} @frappe.whitelist(allow_guest=True) diff --git a/ns_app/public/js/sales_invoice.js b/ns_app/public/js/sales_invoice.js index 037097a..ceb1ad9 100644 --- a/ns_app/public/js/sales_invoice.js +++ b/ns_app/public/js/sales_invoice.js @@ -225,15 +225,43 @@ function run_token_payment(frm, token, dialog) { token: token }, callback(r) { - if (r.message?.success) { + if (r.message?.success) { + + frappe.confirm( + "Payment successful. Save this card for AutoPay?", + () => { + // YES → save to vault + frappe.call({ + method: "ns_app.api.payments.save_to_autopay", + args: { + customer: frm.doc.customer, + token: token + }, + callback(res) { + if (res.message?.success) { + frappe.show_alert({ + message: "AutoPay enabled", + indicator: "green" + }); + } else { + frappe.msgprint(res.message?.error || "Failed to save AutoPay"); + } + } + }); + }, + () => { + // NO + frappe.show_alert({ + message: "Payment completed (not saved)", + indicator: "blue" + }); + } + ); + dialog.hide(); frm.reload_doc(); - - frappe.show_alert({ - message: "Payment successful", - indicator: "green" - }); - } else { + } + else { frappe.msgprint(r.message?.error || "Payment failed"); } }