Kategoriserer danske regnskabs-/ERP-skills, ERP-data-afstemnings-
skill og to devops-workflows (gitea-issue-agent, kanban-workflows)
som Radix-medlemmers AI-agenter kan dele.
Struktur:
skills/<kategori>/<skill-navn>/SKILL.md
skills/<kategori>/<skill-navn>/{references,templates,scripts}/
Indekseret af index.json (genereret af scripts/rebuild_index.py).
Kør `python3 scripts/rebuild_index.py --check` i CI for at fange
synkroniseringsfejl.
4.6 KiB
Three-Way Django Analysis Engine — Coop ↔ Uniconta ↔ Bank
Session-specific implementation notes for building a maintainable three-source reconciliation layer in a Django-based internal finance app.
When to use this pattern
Use when the task has three sources with different semantic roles:
- ERP/accounting ledger, e.g. Uniconta = invoiced/booked postings
- Counterparty/customer statement, e.g. Coop kontoudtog = settlement/detail source
- Bank CSV = actual cash movement / reality check
Do not treat the result as a legal claim automatically. The engine should produce review flags and explainable evidence.
Recommended architecture
Keep the analysis engine separate from import parsing and HTTP views:
apps/core/parsers.py # source-specific import/normalization
apps/core/three_way.py # pure-ish analysis functions
apps/core/management/commands/*.py # import/analyze CLI commands
apps/reconciliation/views.py # dashboard/report presentation only
apps/reconciliation/templates/... # HTML tables/cards
Good public functions in the analysis module:
analyze_three_way_year(year)
build_monthly_summary(year)
build_invoice_statuses(year)
find_unexplained_bank_payments(year)
build_bonus_adjustment_summary(year)
Views should call these functions and render results; avoid embedding reconciliation logic in templates or views.
Batch import command
For folder-based source projects, add a deterministic command that imports all configured source directories:
python manage.py import_all_sources --base-dir /app/source_data
Expected source layout:
Fra Coop/
Fra Uniconta/
Fra bank/
The command should:
- Walk each known directory.
- Infer source from directory, not filename alone.
- Preserve original file, sheet and row identifiers.
- Store row-level import errors.
- Print counts per file and total imported/error counts.
- Be safe to rerun or clearly document duplicate behavior.
Three-way reporting outputs
A useful first report page should show:
- possible amounts the counterparty may owe (
Mulige beløb Coop skylder) - unexplained bank postings (
Uforklarede bankposter) - invoice statuses analyzed
- months with material differences
- month-level totals across all three sources
- bonus/credit/offset summary by period
For each proposed issue, include evidence:
- amount difference
- relevant date range
- invoice/reference, if present
- source counts
- which fields matched and which did not
- score/status and whether manual review is required
Interpretation pitfall
Large totals such as “possible amount owed” are analysis flags, not final claims.
Reasons:
- One bank payment can cover many Coop/Uniconta postings.
- One Coop settlement can cover many invoices.
- Dates may differ between invoice date, statement date, settlement date and bank date.
- Bonus/credit notes may be non-cash accruals or period-based offsets.
- Open-post lists are status snapshots and should be treated separately from ledger/history.
The UI and README should label these as review candidates until group matching and manual approval confirm them.
Matching strategy after basic import
Start with conservative layers:
- Invoice/reference + absolute amount + date tolerance.
- Remaining amount + date tolerance.
- Month-level totals across all three sources.
- Many-to-one and one-to-many group matching.
- Bonus/credit period reconciliation.
- Manual approval/rejection with audit log.
For bank matching, prioritize group matching:
bank payment = sum of many Coop settlement lines = sum of many Uniconta invoices
Use the bank as cash-flow validation, not necessarily as a row-level join target.
Tests to include
Minimum tests for this class of feature:
- invoice is paid when Uniconta, Coop and bank agree
- invoice is flagged when Coop/bank evidence indicates a residual amount
- bank payment without Coop/Uniconta support is flagged as unexplained
- monthly summary calculates Bank-Coop and Bank-Uniconta differences correctly
For Django, add a lightweight test settings module if the normal dev database requires services/permissions:
config/settings/test.py # SQLite, fast local tests
Then run:
DJANGO_SETTINGS_MODULE=config.settings.test python manage.py test
Documentation to update
When this pattern is implemented, update:
- README.md: installation, Docker, import flow, analysis commands, limitations
- ANALYSE.md or ANALYSE_TREVEJS.md: source findings and interpretation
- HANDOFF.md: current status and next recommended steps
- TODO.md/ROADMAP.md: group matching, manual review, bonus expansion