feat(import): Abgabeverträge (DOCX) auswerten und Tiere/Kontakte anreichern
Neuer Parser extract_contracts.py liest die ~1,4k Abgabevertrags-DOCX (\truenas\…\Verträge): er extrahiert aus dem Dokument-Body (zuverlässiger als die Dateinamen) Käufer, Tier(e), Farbschlag, Abgabedatum und Preis — robust gegen Word-Run-Splits (z. B. „F r au"/„3 0,00"); überspringt Vorlage, Abstammungsnachweise und als .docx getarnte .doc. enrich_from_contracts() in merge_and_resolve.py: Käufer werden als Kontakte (IsReceiver) angelegt/zusammengeführt; Tiere werden KONSERVATIV per Rufname (+ DOB-Jahr bei Mehrdeutigkeit) auf eigene Bestandstiere gematcht und erhalten ReceiverContactId, GoHomeDate und Status „abgegeben" — nur wo nicht bereits gesetzt; Konflikte werden geloggt, nicht überschrieben. Jede Übernahme bekommt eine Herkunfts-Zeile („Abgabe an … aus Vertrag … übernommen."). Ergebnis: 1095 Verträge → 783 Tier-Treffer (400 mehrdeutige übersprungen), 274 neue Abnehmer-Kontakte, 153 Tiere mit Abnehmer, 49 mit Abgabedatum, 23 neu „abgegeben". Keine Backend-/Frontend-Änderung nötig (Akte zeigt Abnehmer/ Abgabedatum/Herkunft bereits). SaleContract-Records bewusst nicht erzeugt (bräuchte Migration + ingest-sichere Id — späterer Schritt). Tests: test_extract_contracts.py (Dateiname/Body/Run-Split/Skip-Regeln) + alle bestehenden grün; dotnet 212. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,12 +51,25 @@ preserving everything: `genotype.mapped8locus`, `genotype.rawGenotype` (verbatim
|
||||
|
||||
```sh
|
||||
cd tools/import
|
||||
python extract.py # uses the default source paths
|
||||
python extract.py # xlsx → animals.json / litters.json
|
||||
python extract.py --stammbaeume "<dir>" --wurfchronik "<file.xlsx>"
|
||||
python extract_docx.py # Wurfchronik-Detail.docx → docx_*.json
|
||||
python extract_contracts.py # Abgabeverträge (.docx) → contracts.json
|
||||
python merge_and_resolve.py # → resolved_import.json (DB-ready)
|
||||
```
|
||||
|
||||
Requires Python 3. **Re-runnable / idempotent** — re-run when more files arrive
|
||||
(Wurfchronik `Teil2+`, or new charts).
|
||||
Requires Python 3 (zero third-party deps). **Re-runnable / idempotent** — re-run
|
||||
when more files arrive (Wurfchronik `Teil2+`, new charts, or new contracts).
|
||||
|
||||
`extract_contracts.py` scans the breeder's sale-contract share
|
||||
(`\\truenas\…\Verträge`, ~1.4k `.docx`) and emits one record per contract
|
||||
(buyer, animal call-names, Farbschlag, dates, price, source filename). It skips
|
||||
the blank template, `Abstammungsnachweis`/`Geburtsurkunde` documents, and any
|
||||
file that is not a readable `.docx`. `merge_and_resolve.py` then conservatively
|
||||
folds contracts into the resolved data: buyers become receiver `Contacts`, and
|
||||
unambiguously matched gerbils get `ReceiverContactId` / `GoHomeDate` /
|
||||
`Status=GivenAway` (only where not already set), with a provenance history line.
|
||||
Ambiguous / unmatched animals are counted and skipped, never guessed.
|
||||
|
||||
## Output (`tools/import/output/`, git-ignored except the report)
|
||||
|
||||
@@ -64,6 +77,9 @@ Requires Python 3. **Re-runnable / idempotent** — re-run when more files arriv
|
||||
|---|---|
|
||||
| `animals.json` | deduped animals with genotype, parentRefs, photos, sourceFiles |
|
||||
| `litters.json` | litters from the Wurfchronik |
|
||||
| `docx_animals.json` / `docx_litters.json` | Wurfchronik-Detail.docx rows |
|
||||
| `contracts.json` | one record per Abgabevertrag (buyer, animals, dates, price) |
|
||||
| `resolved_import.json` | merged DB-ready payload consumed by `IngestResolvedService` |
|
||||
| `photos/<slug>/…` | extracted, anchor-mapped images |
|
||||
| `review-report.md` | **human review deliverable** (committed) |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user