Skip to content

ERPNext Daily Posting Engine

URL: https://mkdocs.justinsforge.com/memory/general/reference_erpnext_daily_post/

name: reference_erpnext_daily_post description: forge_erpnext_daily_post.py, idempotent transaction-level finance.db to ERPNext posting; timer 07:20/13:20; state db + ledger map under data/finance/ type: reference

THE ongoing books pipeline (since 2026-06-10). One Journal Entry per finance.db business transaction, posted on the real txn date; mid-month P&L is always live in ERPNext. Replaces the retired one-shot monthly loader forge_erpnext_post_books.py (frozen migration record; never re-run with --apply, it is not idempotent).

SOURCE CUTOVER 2026-06-17: now reads lifeos, not finance.db

  • The poster reads its slice from the lifeos finance schema (source of truth), set via FINANCE_SOURCE=lifeos in forge-erpnext-post.service. Default in code is still finance-db (fallback). lifeos is kept live-current by a replication step appended to forge-finance-sync.service (idempotent finance.db->lifeos forge_finance_migrate_to_lifeos.py --apply, after categorize/recurring/holdings/alerts).
  • Idempotency bridge: lifeos rows carry the original finance.db rowid in legacy_findb_id (finance.transactions + finance.accounts, migrations 0028/0029, populated by the migrate script). The lifeos read path presents those ids, so JE tags FINDB-<id>, the ledger map, and the state db stay byte-identical to the old finance.db path. Verified at flip: slice 3346=3346 0 diffs; status/post-dry-run/post--apply/verify identical between sources.
  • finance.db remains the write lake (SimpleFIN sync + categorize + recurring write there); lifeos mirrors it each sync. Full writer-repoint + finance.db retirement is the later phase.

How it works

  • Reads the business-slice contract (accounts.scope in WIEB/JWVR/NOVA/SIP/GOC, source simplefin/bankcsv, superseded=0) from lifeos (see cutover above; finance.db is the fallback path). Coordination with the finances session via data/finance/COORDINATION.md.
  • Classification comes from forge_books_import.gl_account() (vendor_map.json + code rules + GL_ENTITY_OVERRIDES for the audit F1/F2 fixes: WIEB rent to 5490, Gusto fee to 5420).
  • Idempotency: state db data/finance/erpnext_post_state.db (txn_id primary key, statuses historical/posted/held/cancelled/released) AND each JE carries cheque_no=FINDB-<txn_id>, so ERPNext itself is queryable for duplicates.
  • Per-account contra ledgers from data/finance/erpnext_ledger_map.json: checkings to 1205, business cards to globally-numbered 2431-2435, card payments + intra transfers through per-company 2439 clearing (nets to zero when both legs arrive; sweep reclasses aged unpaired legs to 3700 after review).
  • SEAM 2026-06-08: 3,321 txns seeded status=historical (covered by the migration's monthly JEs). New txns dated on/before the seam are HELD + notified, never auto-posted (release / mark-historical to resolve).
  • Superseded flips auto-cancel the posted JE next run; the surviving twin posts fresh.

Operations

Action Command
Quick state python3 scripts/forge_erpnext_daily_post.py status
Post manually ... post (dry-run) then ... post --apply
Consistency check ... verify (state vs ERPNext + clearing pairing)
Release a held txn ... release --txn-id N / ... mark-historical --txn-id N
Clearing sweep ... sweep then ... sweep --apply
Timer systemctl --user status forge-erpnext-post.timer (07:20/13:20, after finance-sync)
Log logs/erpnext-daily-post.log; failures notify via forge_notify.sh warning

One-time bootstrap commands already run (do NOT re-run): setup-ledgers --apply, seed-historical, reclass-seam --apply, opening-corrections --apply.

Balance-sheet tie (established 2026-06-10)

Every cash/card ledger ties to real statements to the penny as of the seam: card splits via JEs ACC-JV-2026-00088..90, prior-period opening corrections (RE vs 1205) via ACC-JV-2026-00096..99 (JWVR +865.50, NOVA +8,589.51 = pre-2025 card 1042 debt, GOC -444.53, SIP +276.20; WEOP exact 0). ACC-JV-2026-00091..95 are CANCELLED (first correction attempt used a wrong as-of-seam GL filter; the month-28-dated historical JEs made it undercount; documented in AUDIT-INDEPENDENT-2026-06-10.md).

Full audit + findings (rent-as-draws F1, Gusto-fee F2, JE-5 drift F3, JWVR 1715 stray F4): /mnt/workspace/Forge/Finance Migration Summer 2026/AUDIT-INDEPENDENT-2026-06-10.md. Pending Justin review: 2026 YTD rent reclass JE ($5,880 Dr 5490 / Cr 3700, WEOP) and Gusto-fee reclass ($351.78 Dr 5420 / Cr 2320, WEOP); rules already fixed go-forward.

Settlement gross-up companion (Task C, posted 2026-06-10)

forge_erpnext_settlement_grossup.py restates platform revenue to gross (fees 5330, shipping 5320, sales tax 2315, 1320 Platform Payouts in Transit), keyed FINDB-GROSSUP-*; cash-basis true-up keeps net P&L = cash. Inputs: consolidated TikTok CSVs (built by forge_tiktok_statements_consolidate.py from Seller Center xlsx chunks) + live Shopify Payments API. It can cancel/re-create FY2025 PCVs. Monthly cadence: re-run plan --apply after consolidating new TikTok exports (current month always skipped while accruing); FY2026 needs the year-end true-up. Tie-outs: SETTLEMENT-GROSSUP-TIEOUT-2026-06-10.md + 1099K-RECONCILIATION-2026-06-10.md in the Finance Migration workspace folder.

[Fable 5, erpnext-finalize 2026-06-10]