frappe.ui.form.on("Sales Invoice", { refresh(frm) { frm.clear_custom_buttons(); // Only on submitted invoices if (frm.doc.docstatus !== 1) return; if (!frm.doc.customer) return; // Already paid if (frm.doc.outstanding_amount <= 0) { frm.dashboard.add_indicator("Paid", "green"); return; } frm.dashboard.add_indicator("Unpaid", "red"); frm.add_custom_button("Run Payment", () => { run_payment_flow(frm); }, "Actions"); } }); function run_payment_flow(frm) { frm.disable_save(); frappe.call({ method: "ns_app.api.payments.check_autopay", args: { customer: frm.doc.customer }, callback(r) { if (!r.message) { frm.enable_save(); return; } if (r.message.autopay_enabled && r.message.autopay_id) { run_autopay(frm); } else { open_manual_payment_form(frm); } } }); } function run_autopay(frm) { frappe.confirm( `Run AutoPay for $${frm.doc.outstanding_amount}?`, () => { frappe.call({ method: "ns_app.api.payments.run_autopay_payment", args: { invoice: frm.doc.name }, callback(r) { frappe.msgprint("Payment successful"); frm.reload_doc(); } }); }, () => { frm.enable_save(); } ); } function open_manual_payment_form(frm) { const dialog = new frappe.ui.Dialog({ title: "Secure Payment", size: "large", fields: [ { fieldtype: "HTML", fieldname: "loader", options: `
Loading secure checkout…
` }, { fieldtype: "HTML", fieldname: "payment_form", options: `
` } ], primary_action_label: "Close", primary_action() { dialog.hide(); frm.reload_doc(); } }); dialog.show(); frappe.call({ method: "ns_app.api.payments.get_collect_checkout_url", args: { invoice: frm.doc.name }, callback(r) { if (!r.message) { frappe.msgprint("Unable to start payment"); return; } const iframe_html = ` `; document.getElementById("iframe_container").innerHTML = iframe_html; } }); // Poll invoice every 5 seconds const poller = setInterval(() => { frappe.call({ method: "frappe.client.get", args: { doctype: "Sales Invoice", name: frm.doc.name }, callback(r) { if (r.message && r.message.outstanding_amount <= 0) { clearInterval(poller); dialog.hide(); frm.reload_doc(); frappe.msgprint("Payment successful!"); } } }); }, 5000); }