3.8 KiB
NS App – ERPNext Custom Integrations
Overview
NS App is a custom ERPNext application that:
Adding a manual payment form using Collect.js Processing secure card payments through NMI Optionally saving payment methods to the NMI Customer Vault Storing the returned vault ID on the ERPNext Customer for future autopay use
This part of the app is designed to integrate directly into the Sales Invoice workflow.
Features Secure card entry using NMI Collect.js (tokenization) Manual payment dialog inside ERPNext Optional “Subscribe to Autopay” checkbox Conditional vault creation in NMI Storage of customer_vault_id in ERPNext Customer Configurable enable/disable of autopay via site_config.json
Requirements ERPNext / Frappe Bench environment NMI gateway account Collect.js enabled in NMI Access to modify site_config.json
Installation
- Get the app cd ~/frappe-bench bench get-app git@git.nsinnovations.net:nsinnovations/ns_erpnext_app.git --skip-assets
- Install on site bench --site "site name" install-app ns_app
- Build and restart bench build bench restart
Configuration
Edit site configuration: nano ~/frappe-bench/sites/site-name/site_config.json
Add:
{ "nmi_security_key": "your_nmi_security_key", "enable_autopay_signup": 0 } Notes nmi_security_key is required for all payment and vault operations enable_autopay_signup controls whether the checkbox actually triggers vault creation Frontend Behavior
The payment dialog includes:
Cardholder Name Billing ZIP Secure card fields via Collect.js “Subscribe to Autopay” checkbox
If the checkbox is selected and autopay is enabled in config, the backend will attempt to create a vault entry.
Backend Flow: Payment Collect.js generates a payment token Token is sent to backend API Backend sends transaction to NMI Payment is processed Autopay (Optional)
If enabled and selected:
Backend sends customer_vault=add_customer request to NMI Uses the same payment token Parses response for customer_vault_id Saves ID to ERPNext Customer Example Vault Request vault_data = { "security_key": frappe.conf.get("nmi_security_key"), "customer_vault": "add_customer", "payment_token": token, "first_name": first_name, "last_name": last_name, "zip": billing_zip } Error Handling
Vault creation is wrapped in a try/except block to prevent payment failures:
try: if int(save_autopay or 0): # vault logic pass except Exception: frappe.log_error(frappe.get_traceback(), "Autopay Vault Error") Testing Strategy
Before enabling in production:
Set in site_config.json:
"enable_autopay_signup": 0 Verify: Payments process correctly No vault entries are created
Enable autopay:
"enable_autopay_signup": 1 Test: Checkbox unchecked → no vault Checkbox checked → vault created and saved Deployment Notes Do not expose autopay functionality until fully tested Keep enable_autopay_signup disabled in production until ready Always run: bench build bench restart
Troubleshooting:
- App not found
Ensure app is in apps.txt:
nano ~/frappe-bench/sites/apps.txt
Add:
ns_app
- ModuleNotFoundError
Ensure app is installed in environment:
./env/bin/pip install -e apps/ns_app Asset build errors
Skip during install:
bench get-app --skip-assets
Then fix frontend paths before running bench build.
Vault not saving
Check logs:
frappe.log_error(response.text, "Vault Response")
Verify:
customer_vault_id is returned Security key is correct File Structure apps/ns_app/ ├── ns_app/ │ ├── api/ │ │ └── payments.py │ ├── public/ │ │ └── js/ │ └── hooks.py ├── setup.py ├── pyproject.toml └── MANIFEST.in
Security Notes: Never store raw card data Always use Collect.js tokenization Keep nmi_security_key private Use HTTPS for all requests