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 1. Get the app cd ~/frappe-bench bench get-app git@git.nsinnovations.net:nsinnovations/ns_erpnext_app.git --skip-assets 2. Install on site bench --site "site name" install-app ns_app 3. 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: 1. App not found Ensure app is in apps.txt: nano ~/frappe-bench/sites/apps.txt Add: ns_app 2. 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