Upload to erp
Template for yearly bookkeeping for small holding companies. Country-agnostic (DK example), ERP-agnostic (Ofinda example).
npx -y skills add NOGIT007/holding-accounting --skill upload-to-erpAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Push the year's bookkeeping (journal lines from regnskab{YYYY}/ledger.db) into the configured ERP system. Trigger when the user asks to "upload to ERP", "push til Ofinda", "send to ERP", or "post to {erp_name}" after the bookkeeping has been approved. Reads ERP_CONNECTOR from settings/.env and dispatches to connectors/{erp}/upload.py.
SKILL.md
3.6 KB, 770 tokens by cl100k_base, as published. Nobody here has run it
Upload to ERP
Optional final phase. Pushes the year's journal lines into an external ERP system after the user has approved the bookkeeping.
When to invoke
Only after the user has explicitly approved the bookkeeping (see the approval gate in the yearly-bookkeeping orchestrator skill). Do not invoke this on your own — wait for the user to ask.
How it works
- Read
settings/.envto findERP_CONNECTOR(e.g.ERP_CONNECTOR=ofinda). - Run
python connectors/{erp}/upload.py {YYYY}as a dry-run first. Show the user what would happen. - If the dry-run looks right, ask the user to confirm in chat.
- On confirmation, run with
--execute. The connector will still ask for an interactiveyesbefore any destructive call.
Dry-run output
The dry-run prints:
- Authentication (succeeds or fails — credentials test).
- Journal resolution (which kassekladde / daybook is the target).
- The count of lines to push, and the first 5 with debet/kredit.
- The list of files referenced from
Bilag-filthat the connector will (or cannot) attach.
If the count looks wrong, the journal is wrong, or auth fails — halt and surface the error to the user before retrying.
Real upload
cd connectors/ofinda # or your ERP folder
python upload.py {YYYY} --execute
By default the script asks for an interactive yes before any POST/DELETE. Pass --yes to skip the prompt only if the user has confirmed twice in chat.
Replace existing lines
If the year has already been pushed and the user is re-uploading after changes:
python upload.py {YYYY} --execute --replace
This deletes the existing lines on the journal first, then re-posts. Use only after the user has explicitly asked for --replace. Otherwise prefer to append.
Skipping system-generated entries
By default, three bilag IDs are skipped — primosaldi, year-end close, presentation reclasses. The connector exposes --skip-bilag to override this list. If your numbering differs, update note{YYYY}.md with the right list and pass it through.
File attachments
For Ofinda specifically, binary file upload is not supported via API as of 2026 — the public swagger only documents file metadata. The connector ends every successful run with a list of files to attach manually in the Ofinda UI per voucher. Walk the user through that list.
For other ERPs, check connectors/{erp}/README.md for whether file attachment is supported.
Verifying the push
After a real upload, the connector prints:
- The number of lines posted.
- The journal's URL in the ERP UI (if the ERP exposes one).
- The list of files to attach manually.
Open the ERP UI, navigate to the journal, and verify:
- Line count matches.
- Trial balance still nets to zero.
- The journal is locked / saved as expected by your ERP's normal workflow.
What this skill does NOT do
- It does not modify the local workbook or
ledger.db. The push is one-way. - It does not create the ERP company or the journal type. Those must already exist.
- It does not handle partial-year uploads. The connector pushes the entire year as one batch.
- It does not retry on failure. If the upload fails partway through, halt and let the user decide whether to use
--replaceto wipe and retry.