Initial import: 10 Radix skills across 3 categories
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.
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
# Coop ↔ Uniconta Reconciliation Reference (Aktualiseret 2025-05-26)
|
||||
|
||||
Konkrete felter, mappings og pitfalls fra det aktuelle Coop-Uniconta projekt.
|
||||
|
||||
---
|
||||
|
||||
## Coop (SAP export) — Kontoudtog.xlsx
|
||||
|
||||
| Kolonne | Navn | Type | Match-brug |
|
||||
|---------|------|------|------------|
|
||||
| Entry Date | Entry Date | datetime | Sekundær |
|
||||
| Document Type | Document Type | **string** | **Filter + match-type** |
|
||||
| Document Date | Document Date | datetime | Sekundær |
|
||||
| **Posting Date** | Posting Date | **datetime** | **Primær dato** |
|
||||
| **Reference** | Reference | **string (75% non-null)** | **Primær match-nøgle** |
|
||||
| Net Due Date | Net Due Date | datetime | Forfaldsdato |
|
||||
| **Amount** | Amount in Local Currency | **float** | **Primær beløb** |
|
||||
| Document Currency | Local Currency | string ('DKK') | Filter |
|
||||
| **Document Number** | Document Number | int | **Audit/trace** |
|
||||
| Text | Text | string (20% non-null) | Sekundær match |
|
||||
| Payment Reference | Payment Reference | string (12% non-null) | OCR/trace |
|
||||
| User Name | User Name | string | Audit |
|
||||
|
||||
### Coop Document Types (2024-2025)
|
||||
| Type | Andel | Beskrivelse | Uniconta-modpart |
|
||||
|------|-------|-------------|----------------|
|
||||
| RE | ~50% | Regning/betaling | Betaling/Faktura |
|
||||
| ZV | ~15% | Udbetalingsforslag/faktura | Betaling |
|
||||
| RG | ~6% | Kontoafstemning | Kreditnota |
|
||||
| KG | ~5% | Kontoafstemning gruppe (bonus/rabat) | Kreditnota |
|
||||
| ZC | ~3% | Kreditering | Kreditnota |
|
||||
| ZP | ~0.4% | Betaling | Betaling |
|
||||
| XX | ~0% (filtreret fra) | Manuelt bogført/migrering | — |
|
||||
|
||||
**VIGTIGT:** ZV-poster er positive fakturaer udstedt til kunder. De har typisk **ingen Reference/Faktura-nummer** og matches via `abs(beløb) + dato` mod Uniconta Betalinger.
|
||||
|
||||
---
|
||||
|
||||
## Uniconta — Coop danmark.xlsx
|
||||
|
||||
### Fil-struktur
|
||||
- Række 1: Konto-info (Checked, Konto, Kontonavn, Adresse, Bynavn)
|
||||
- Række 2-3: Tomme
|
||||
- Række 4: Kolonne-headers: Dato, Faktura, Forfaldsdato, Bilag, Tekst, Beløb, Resterende, Forfalden, Konteringstype, Sum
|
||||
- Række 5+: Data
|
||||
|
||||
| Kolonne | Navn | Type | Match-brug |
|
||||
|---------|------|------|------------|
|
||||
| **Dato** | Dato | **datetime** | **Primær dato** |
|
||||
| **Faktura** | Faktura | **mixed int/str, 0=ingen** | **Primær match-nøgle** |
|
||||
| Forfaldsdato | Forfaldsdato | datetime | Sekundær |
|
||||
| Bilag | Bilag | mixed int/str | Audit |
|
||||
| **Tekst** | Tekst | **string** | **Tekst-match** |
|
||||
| **Beløb** | Beløb | **float/tekst** | **Primær beløb** |
|
||||
| Resterende | Resterende | float | Filter |
|
||||
| Forfalden | Forfalden | float | Filter |
|
||||
| **Konteringstype** | Konteringstype | **string** | **Filter + match-bonus** |
|
||||
| Sum | Sum | float | IGNORE — løbende saldo |
|
||||
|
||||
### Uniconta Konteringstyper
|
||||
| Type | Beskrivelse | Match-modpart (Coop) |
|
||||
|------|-------------|---------------------|
|
||||
| Faktura | Faktura udstedt | RE (betaling) eller ZV |
|
||||
| Betaling | Betaling modtaget | RE, ZP, ZV |
|
||||
| Kreditnota | Kreditnota | RG, ZC, KG |
|
||||
| Primo | Primo-saldo | XX (filtreres fra) |
|
||||
| Afslutning | Årsafslutning | — |
|
||||
| Overførsel | Overførselsbilag | — |
|
||||
| Manuel | Manuel posting | — |
|
||||
| Rabat | Rabat | KG |
|
||||
|
||||
---
|
||||
|
||||
## Match-nøgle-observationer
|
||||
|
||||
### Fakturanumre overlapper IDENTISK
|
||||
- Coop `Reference` og Uniconta `Faktura` bruger **identiske 4-5 cifrede tal**.
|
||||
- Eksempler: 46344, 44907, 48456, 49495, 51519
|
||||
- **2.970 unikke RE-references findes som Faktura-numre i Uniconta.**
|
||||
- Dette er den stærkeste match-signal — langt stærkere end beløb+dato alene.
|
||||
|
||||
### Modsat fortegn er NORMALT
|
||||
| Coop type | Coop fortegn | Uniconta type | Uniconta fortegn | Match |
|
||||
|-----------|-------------|---------------|-----------------|-------|
|
||||
| RE (betaling) | Negativ (-) | Faktura | Positiv (+) | abs(beløb) |
|
||||
| ZV (faktura) | Positiv (+) | Betaling | Negativ (-) | abs(beløb) |
|
||||
| RG (kreditnota) | Positiv (+) | Kreditnota | Negativ (-) | abs(beløb) |
|
||||
| KG (rabat) | Positiv (+) | Kreditnota | Negativ (-) | abs(beløb) |
|
||||
|
||||
**Implikation:** Match-motoren SKAL sammenligne `abs(beløb)`, ikke rå beløb.
|
||||
|
||||
### Dato-tolerance
|
||||
- Faktura-reference matches: ±21 dage fungerer fint
|
||||
- Generelle beløb+dato matches: ±21 dage fanger de fleste
|
||||
- ZV↔Betaling matches: ±30 dage anbefales (betalingsforslag vs. faktura)
|
||||
|
||||
---
|
||||
|
||||
## Normalisering
|
||||
|
||||
### Beløb (dansk format)
|
||||
Nogle Uniconta-celler indeholder tekststrenge som `-2.543.803,93`:
|
||||
```python
|
||||
def parse_danish_number(val):
|
||||
if pd.isna(val) or val is None: return None
|
||||
if isinstance(val, (int, float)): return float(val)
|
||||
s = str(val).strip().replace('\xa0','').replace('\u202f','').replace(' DKK','')
|
||||
if s.lower() in ('nan',''): return None
|
||||
if s.endswith('.0'): s = s[:-2]
|
||||
if '.' in s and ',' in s:
|
||||
s = s.replace('.','').replace(',','.')
|
||||
elif ',' in s:
|
||||
s = s.replace(',','.')
|
||||
try: return float(s)
|
||||
except: return None
|
||||
```
|
||||
|
||||
### Tekst
|
||||
```python
|
||||
def normalize_text(t):
|
||||
if not t or pd.isna(t): return ''
|
||||
return re.sub(r'\s+',' ',str(t).lower().strip()).strip()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Konto-specifikt mønster
|
||||
|
||||
### "Coop 0010014808"
|
||||
- Uniconta indeholder mange poster med teksten "Coop 0010014808"
|
||||
- Beløb varierer fra -1.155.458,24 til -65.000
|
||||
- Nogle har fakturanummer, andre har ikke
|
||||
- Dette ligner en **samlet konto-kontering** for Coop-omsætning, ikke enkeltfakturaer
|
||||
- Disse poster er svære at matche automatisk og bør behandles særskilt
|
||||
|
||||
### Bonus/rabat-poster
|
||||
- Coop KG: "CCM Purchasing Rebate Credit"
|
||||
- Uniconta Rabat: sjælden, men findes
|
||||
- Disse bør matches separat via beløb + dato + bonus-tekst
|
||||
|
||||
---
|
||||
|
||||
## Specifikke problemer opdaget (V6.1)
|
||||
|
||||
1. **Faktura 46344** — Uniconta Faktura +441.720, Coop RE -441.720, men også Uniconta Betaling -430.732,50. Delvis kreditnota.
|
||||
|
||||
2. **Faktura 51519** — Uniconta Faktura +244.926, Coop RE -244.926, Uniconta Betaling -244.926. Dobbeltregistrering (Coop+Uni betaling).
|
||||
|
||||
3. **Faktura 48323** — Ingen Coop-betaling, men Uniconta Betaling -240.000 findes. Faktura er BETALT via Uniconta-betaling.
|
||||
|
||||
4. **Faktura 47140/47347 (DELVIST BETALT)** — Coop har både negativ og positiv RE med samme reference. Netto-sum giver korrekt status.
|
||||
|
||||
5. **Dobbelt-registrering** — Samme betaling findes som både Coop RE og Uniconta Betaling. Ved summing af begge får man 2x betalt. Løsning: brug netto-sum og dedupliker.
|
||||
|
||||
6. **MR8M-modregninger** — Positive Coop RE med "MR8M Credit memo" tekst er modregninger. De skal trækkes fra i netto-beregning, ikke lægges til med `abs()`.
|
||||
|
||||
---
|
||||
|
||||
## Afstemningsstrategi der virkede (V6.1 anbefalet)
|
||||
|
||||
**Fase 1: Reference-match (RE↔Faktura, RG↔Kreditnota)**
|
||||
- Krav: Coop.Reference == Uniconta.Faktura
|
||||
- Krav: abs(Coop.Amount) ≈ abs(Uniconta.Amount) ±5 kr (tolerance)
|
||||
- Krav: Dato ±21 dage
|
||||
- Bonus: Korrekt konteringstype
|
||||
- Score ~250
|
||||
- Resultat 2024-2025: ~2.421 matches
|
||||
|
||||
**Fase 2: ZV↔Faktura**
|
||||
- Coop ZV (positive fakturaer) matcher Uniconta Faktura
|
||||
- abs(beløb) ±5 kr + dato ±21 dage
|
||||
- Bonus: Document Number == Faktura
|
||||
- Resultat 2024-2025: ~173 matches
|
||||
|
||||
**Fase 3: RE↔Betaling uden reference**
|
||||
- Coop RE uden fakturanummer matcher Uniconta Betaling
|
||||
- abs(beløb) ±5 kr + dato ±21 dage
|
||||
- Bonus: tekst-lighed
|
||||
- Resultat 2024-2025: ~192 matches
|
||||
|
||||
**Fase 4: Generel abs(beløb)+dato**
|
||||
- abs(beløb) ±5 kr + dato ±21 dage
|
||||
- Konteringstype-bonus, tekst-lighed, reference-bonus
|
||||
- Score ≥ 40
|
||||
- Resultat 2024-2025: ~1.939 matches
|
||||
|
||||
**Fase 5: Mange-til-én**
|
||||
- Sum af 2-3 Uniconta-poster == Coop-postering ±5 kr
|
||||
- Dato ±14 dage, max 25 kandidater
|
||||
- Resultat 2024-2025: ~276 matches
|
||||
|
||||
**Total matches 2024-2025: 5.001 ud af 7.328 Coop / 6.717 Uniconta (~68%)**
|
||||
|
||||
**Uafstemt: ~2.327 Coop (31,8%) + ~2.211 Uniconta (32,9%)**
|
||||
|
||||
---
|
||||
|
||||
## Faktura-status: Netto-baseret + deduplikering
|
||||
|
||||
### Dobbelt-registrering
|
||||
Samme betaling findes som både Coop RE og Uniconta Betaling.
|
||||
|
||||
```python
|
||||
# Beregn NETTO Coop betalinger (ikke abs-sum!)
|
||||
coop_net = sum(c['amount'] for c in coop
|
||||
if c['reference'] == fnr and c['doc_type'] in ('RE','ZP'))
|
||||
coop_paid = abs(coop_net) if coop_net < 0 else 0
|
||||
|
||||
# Beregn NETTO Uniconta betalinger
|
||||
uni_net = sum(u['amount'] for u in uni
|
||||
if u['faktura'] == fnr and u['konteringstype'] == 'Betaling')
|
||||
uni_paid = abs(uni_net) if uni_net < 0 else 0
|
||||
|
||||
# Dedupliker
|
||||
if coop_paid > 0 and uni_paid > 0:
|
||||
if abs(coop_paid - uni_paid) <= AMT_TOL:
|
||||
betalt = coop_paid # Samme betaling
|
||||
else:
|
||||
betalt = max(coop_paid, uni_paid)
|
||||
elif coop_paid > 0: betalt = coop_paid
|
||||
elif uni_paid > 0: betalt = uni_paid
|
||||
else: betalt = 0
|
||||
```
|
||||
|
||||
**Resultat:** 2.968 BETALT, 2 DELVIST, 186 UBETALT
|
||||
|
||||
---
|
||||
|
||||
## Bevar original rådata
|
||||
|
||||
Exportér ALTID:
|
||||
- Original række-nummer (Excel-rækkeindeks)
|
||||
- Filnavn og ark-navn
|
||||
- Rå JSON med alle kolonner
|
||||
Så brugeren kan spore enhver match tilbage til kildefilen.
|
||||
Reference in New Issue
Block a user