add additional commits #6
173
README.md
Normal file
173
README.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
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 <repo> --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
|
||||||
|
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@ import frappe
|
|||||||
import requests
|
import requests
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from frappe.utils import nowdate
|
from frappe.utils import nowdate
|
||||||
|
from frappe.utils import cint
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
|
|||||||
Reference in New Issue
Block a user