Verify the ERPNext integration live and fix the defects it found (Phase F4)

Ran the push flow against ERPNext 15.121.6 on a plain site and on a site with India Compliance 15.32.0 (podman, scripts/erpnext-e2e). 15 ignored live tests pass on both.

Fixes, each covered by a mock-based test:
- load_options no longer fails on a plain site: the India Compliance-only gstin field is dropped on a 417 and retried.
- Code-less rows with fractional hours or minutes send stock_uom, since ERPNext defaults it to Nos.
- A created document whose total differs from Voiced's (ERPNext's default Banker's Rounding on half-paise ties) is recorded as a conflict, kept as a draft, not submitted and not given a PDF. The message names Commercial Rounding as the fix.
- An existing customer address is reused instead of creating a duplicate on every first push. A bare creation order-by is not used with a Dynamic Link filter.
- A re-adopted document no longer gets a second copy of the PDF.
- Reverse charge: India Compliance rejects is_reverse_charge unless tax rows are negative RCM amounts, so the flag is sent as 0 with a warning that the invoice lands as a normal taxed invoice.
- The 16-character name rule is checked locally in mirror mode under India Compliance, and a TDS-only payment is refused locally with the reason.

Payment Entry mapping verified: bank_account is the Account name (paid_to), paid and received amounts equal the cash received, allocated_amount is cash plus TDS, and TDS is one positive deductions row. The integration user needs the Accounts User and Sales User roles.

Not verified: ERPNext v14 and v16, other India Compliance versions, the Tauri commands and UI against a live site, SEZ and overseas customers, UTGST supplier states, TLS sites, e-invoicing.
This commit is contained in:
2026-10-04 22:09:03 +05:30
parent 2ffbf0f66c
commit 8dc4d85e14
11 changed files with 1554 additions and 39 deletions
+66
View File
@@ -0,0 +1,66 @@
# Lean ERPNext v15 stack for Voiced's live integration tests (project name: voiced-erp).
# db + redis + backend (gunicorn, published on 127.0.0.1:8088) + one worker. No nginx/websocket/scheduler.
# setup.sh starts it in order (db, redis, configurator, then backend and worker); do not `up` it blindly.
# Image: voiced-erp-ic:v15 = frappe/erpnext v15 + the india_compliance app files (see Containerfile.ic).
name: voiced-erp
services:
db:
image: docker.io/library/mariadb:11.8
container_name: voiced-erp-db
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
- --innodb-buffer-pool-size=256M
environment:
MARIADB_ROOT_PASSWORD: admin
volumes:
- voiced-erp-db:/var/lib/mysql
redis:
image: docker.io/library/redis:8.6-alpine
container_name: voiced-erp-redis
configurator:
image: localhost/voiced-erp-ic:v15
container_name: voiced-erp-configurator
restart: "no"
entrypoint: ["bash", "-c"]
command:
- >
wait-for-it -t 120 db:3306;
ls -1 apps > sites/apps.txt;
bench set-config -g db_host db;
bench set-config -gp db_port 3306;
bench set-config -g redis_cache redis://redis:6379;
bench set-config -g redis_queue redis://redis:6379;
bench set-config -g redis_socketio redis://redis:6379;
bench set-config -gp socketio_port 9000;
volumes:
- voiced-erp-sites:/home/frappe/frappe-bench/sites
- voiced-erp-logs:/home/frappe/frappe-bench/logs
depends_on:
- db
- redis
backend:
image: localhost/voiced-erp-ic:v15
container_name: voiced-erp-backend
ports:
- "127.0.0.1:8088:8000"
volumes:
- voiced-erp-sites:/home/frappe/frappe-bench/sites
- voiced-erp-logs:/home/frappe/frappe-bench/logs
worker:
image: localhost/voiced-erp-ic:v15
container_name: voiced-erp-worker
command: ["bench", "worker", "--queue", "short,default,long"]
volumes:
- voiced-erp-sites:/home/frappe/frappe-bench/sites
- voiced-erp-logs:/home/frappe/frappe-bench/logs
volumes:
voiced-erp-db:
voiced-erp-sites:
voiced-erp-logs: