feat(deploy): TrueNAS Custom-App + Auto-Deploy, plus aufgelaufene Arbeit
Deployment: - custom-app.compose.yaml: self-contained Compose fuer TrueNAS "Custom App" (absolute Host-Bind-Pfade, postgres:18, pull_policy always, Port 8090) - scripts/truenas-deploy.sh: Host-Skript create/redeploy via midclt (App bleibt unter Apps sichtbar) inkl. Image-Pull + Health-Check - ci.yml Deploy-Job: laeuft auf ubuntu-latest-Runner, kopiert Deploy-Dateien per SSH auf den NAS-Host und triggert truenas-deploy.sh (statt runs-on goldeye) - compose.yaml/.env.example: postgres:18 (Locale-Match zur Quell-DB), Port 8090 - .gitignore: .agents/, tools/rag/, deploy/truenas/.env (Secrets/Scratch) Aufgelaufene Feature-Arbeit (verified/Freeze, Migrationen, Import-Triage): - GerbilOverride/VerifiedGerbil-Endpoints + GerbilSnapshotService + Tests - EF-Migrationen (ShowInChronicle, Stillborn, BirthOrder, ManualFlag, DSGVO) - Frontend VerifizierteTierePage + verified-API + e2e-Spec - diverse Import-/Triage-Skripte und -Tests Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
tools/import/ask_breeder_krumel.py
Normal file
24
tools/import/ask_breeder_krumel.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ticket_id = "21c8ff24-cc03-4508-b6c6-849ab36ba5b2"
|
||||
url = f"http://localhost:5179/feedback/{ticket_id}"
|
||||
|
||||
payload = {
|
||||
"question": "Hallo! In den vorliegenden Originaldokumenten (Wurfchronik und Stammbäume) war leider kein Todesdatum für Krümmel eingetragen. Wenn du uns sein Todesdatum verrätst, können wir es gerne nachtragen. Wann ist er denn verstorben?"
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {ticket_id} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -200,7 +200,16 @@ def parse_detail(text):
|
||||
geno = ""
|
||||
if dob:
|
||||
tail = text[dob.end():]
|
||||
tail = re.sub(r"^\s*/?\+?\s?\d[\d.]*", "", tail) # drop any /+death remnant
|
||||
# FIX (ab8fdb0b): broaden the leading death-marker strip BEFORE the
|
||||
# looks_like_genotype check, so a death marker right after the DOB never
|
||||
# leaks into the genotype string. Covers: bare "/+", "/+<numeric date>",
|
||||
# "/+<year>", "/+<Textmonth>'<year>" (e.g. "/+April'2017"), "/+ ," and a
|
||||
# leading "+<date>" (e.g. "+09.07.2017" — Fegur). The full-text DEATH regex
|
||||
# still captures the actual death date, so no data is lost.
|
||||
tail = re.sub(
|
||||
r"^\s*/?\+\s*"
|
||||
r"(?:\d{1,2}\.\d{1,2}\.(?:\d{4}|\d{2})|\d{4}|[A-Za-zÄÖÜäöü]+'?\s?\d{2,4})?",
|
||||
"", tail)
|
||||
tail = tail.lstrip(" ,").strip()
|
||||
# FIX-4 (Skarlett): strip trailing "/ +YEAR" death-year artifacts leaked from compact
|
||||
# chart cells (e.g. "… rere / +2018"). The DEATH regex still captures the year from
|
||||
@@ -283,7 +292,10 @@ def extract_stammbaum(path):
|
||||
and not looks_like_animal_name(cell):
|
||||
farbschlag = cell
|
||||
used.add((c, rr))
|
||||
used.add((c, r))
|
||||
used.add( (c, r) )
|
||||
|
||||
if "verpaarung" in name.lower():
|
||||
continue
|
||||
|
||||
g = parse_detail(t) if compact else (dob, death, geno)
|
||||
genodict = gt.parse(geno)
|
||||
|
||||
@@ -129,6 +129,35 @@ def extract(docx_path: str):
|
||||
last_dates = _LAST_DATE_RE.findall(dob_raw)
|
||||
dob_clean = _norm_dob(last_dates[-1] if last_dates else dob_raw)
|
||||
|
||||
# Map 22-Wurf and 23-Wurf to their correct alphabetical sequence name based on DOB
|
||||
if litter_id == "22-Wurf":
|
||||
dob_map = {
|
||||
"17.06.2023": "V22-Wurf",
|
||||
"13.07.2023": "X22-Wurf",
|
||||
"20.07.2023": "Y22-Wurf",
|
||||
"24.07.2023": "Z22-Wurf"
|
||||
}
|
||||
if dob_clean in dob_map:
|
||||
litter_id = dob_map[dob_clean]
|
||||
elif litter_id == "23-Wurf":
|
||||
dob_map = {
|
||||
"03.10.2023": "F23-Wurf",
|
||||
"06.10.2023": "G23-Wurf",
|
||||
"10.10.2023": "H23-Wurf",
|
||||
"17.10.2023": "I23-Wurf",
|
||||
"31.10.2023": "J23-Wurf",
|
||||
"04.11.2023": "K23-Wurf",
|
||||
"11.11.2023": "L23-Wurf",
|
||||
"17.11.2023": "M23-Wurf",
|
||||
"20.11.2023": "N23-Wurf",
|
||||
"01.12.2023": "O23-Wurf",
|
||||
"02.12.2023": "P23-Wurf",
|
||||
"03.12.2023": "Q23-Wurf",
|
||||
"05.12.2023": "R23-Wurf"
|
||||
}
|
||||
if dob_clean in dob_map:
|
||||
litter_id = dob_map[dob_clean]
|
||||
|
||||
litter = {
|
||||
"litterId": litter_id,
|
||||
"dob": dob_clean,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,14 +5,14 @@ _Automatisch erzeugt von `tools/import/extract.py` — **noch nichts in die Date
|
||||
## Überblick
|
||||
|
||||
- Rohe Tier-Einträge aus den Stammbäumen: **2548**
|
||||
- Nach Zusammenführung (eindeutige Tiere): **1044**
|
||||
- davon mit Geburtsdatum: 685
|
||||
- in mehreren Dateien gefunden (Dubletten zusammengeführt): 476
|
||||
- Konflikte zur Klärung: **7**
|
||||
- Nach Zusammenführung (eindeutige Tiere): **1042**
|
||||
- davon mit Geburtsdatum: 683
|
||||
- in mehreren Dateien gefunden (Dubletten zusammengeführt): 477
|
||||
- Konflikte zur Klärung: **8**
|
||||
- Mehrdeutige / unvollständige Einträge (ohne Name+Datum): **380**
|
||||
- Fotos zugeordnet: **435**
|
||||
- Würfe aus der Wurfchronik: **752**
|
||||
- Tiere mit Wurf verknüpft: **270** (davon über Geburtsdatum **und** Eltern: 170, nur über Geburtsdatum: 100; mehrdeutig: 17)
|
||||
- Tiere mit Wurf verknüpft: **270** (davon über Geburtsdatum **und** Eltern: 174, nur über Geburtsdatum: 96; mehrdeutig: 16)
|
||||
- Würfe mit Datenqualitäts-Hinweisen: 113 (+ 138 Zeilen mit abweichendem Spaltenschema)
|
||||
|
||||
## Zusammenführungs-Schlüssel
|
||||
@@ -37,6 +37,7 @@ Gleiches Tier (Name+Datum), aber widersprüchliche Angaben in verschiedenen Date
|
||||
| Ella | 10.06.2019 | Aa C D- ee[f] GG P- spsp // Aa Cc[chm] D- ee[f] GG P- spsp // Aa Cc[chm] D- ee[f] UwUw P- spsp | Algierfuchsschimmel, hell | 03.02.2023 // 31.01.2023 | Stammbaum von Akio Kids, Stammbaum von CP-Fuchs, CP-Sa Sp von Unity, Stammbaum von Ella, Stammbaum von Picus Son, Stammbaum von Valentino Firehearts Kids |
|
||||
| Lui von den Kleinen Chaoten | 16.04.2021 | Aa Cc[chm] DD ee[f] Gg PP Spsp // Aa c[chm]c[chm] D- Ee[f] Gg PP spsp | — | 15.12.2020 | Stammbaum von Alberto Kids, Stammbaum von Picus Son |
|
||||
| Osamu | 10.12.2015 | AA CC DD ee gg P- spsp // AA CC DD ee gg PP spsp // AA CC DD ee uw[d]uw[d] PP spsp | — | 01.10.2020 // 18.12.2020 | Stammbaum von Danako, Stammbaum von Ella, Stammbaum von Jin, Stammbaum von Kazuya, Stammbaum von Kentucky, Stammbaum von Martin, Stammbaum von Picus Son, Stammbaum von Rainny, Stammbaum von Ren, Stammbaum von South Dakota, Stammbaum von Stella Kids, Stammbaum von Tennessee, Stammbaum von Zenon von Elea |
|
||||
| Taro von den kleinen Chaoten | 01.09.2012 | Aa Cc[chm] D- Ee Gg Pp spsp // aa Cc[chm] DD EE GG PP spsp | — | 01.10.2015 // 21.09.2012 | Stammbaum von Danako, Stammbaum von Kalea |
|
||||
| Quebec v.d. Kleinen Chaoten | 21.06.2014 | aa Cc[chm] dd Ee Gg Pp spsp // aa Cc[chm] dd Ee Uwuw[d] Pp spsp // aa Cc[chm] dd Ee gg Pp spsp | — | 21.10.2016 | Stammbaum von Ella, Stammbaum von Jin, Stammbaum von Kazuya, Stammbaum von Martin, Stammbaum von Picus Son, Stammbaum von Rainny, Stammbaum von Ren, Stammbaum von South Dakota, Stammbaum von Tennessee, Stammbaum von Zenon von Elea |
|
||||
| | 20.04.2024 | Aa C- dd Ee Gg P- Spsp | Dilute Agouti Kragenschecke // Dilute Kohlfuchs Kragenschecke DP | — | Stammbaum von Fire Kids, Stammbaum von Stella Kids |
|
||||
| Hanami | 10.09.2015 | aa Cc[chm] D- Ee gg P- spsp // aa Cc[chm] D- Ee uw[d]uw[d] P- spsp | — | 02.01.2020 // 12.12.2019 // 14.01.2020 | Stammbaum von Hana, Stammbaum von Kentucky, Stammbaum von Rainny, Stammbaum von Ren, Stammbaum von Stella Kids, Stammbaum von Vance, Stammbaum von Zac (Vance.Dorie) |
|
||||
@@ -158,8 +159,8 @@ Diese Tokens stehen weiter in `rawGenotype`/`unmappedTokens` — Entscheidung (M
|
||||
|
||||
| Token | Vorkommen | Bedeutung (Vermutung) |
|
||||
|---|---|---|
|
||||
| `/+` | 7 | ? |
|
||||
| `[meliert]` | 4 | ? |
|
||||
| `2` | 3 | ? |
|
||||
| `(Kragen)` | 3 | ? |
|
||||
| `/` | 3 | ? |
|
||||
| `-g` | 2 | ? |
|
||||
@@ -167,19 +168,19 @@ Diese Tokens stehen weiter in `rawGenotype`/`unmappedTokens` — Entscheidung (M
|
||||
| `Tumor` | 2 | ? |
|
||||
| `!` | 2 | ? |
|
||||
| `C(C)` | 2 | Schreibweise (C trägt c) |
|
||||
| `/18.02.2020` | 2 | ? |
|
||||
| `(KW` | 2 | ? |
|
||||
| `[WFNZ-Maroon]` | 1 | ? |
|
||||
| `/+April'2017` | 1 | ? |
|
||||
| `[meliert]-[DP]` | 1 | ? |
|
||||
| `!Knickschwanz-Gen!` | 1 | ? |
|
||||
| `-09.09.2018` | 1 | ? |
|
||||
| `08-09.09.2018` | 1 | ? |
|
||||
| `[DP?]` | 1 | ? |
|
||||
| `/+Dezember'2014` | 1 | ? |
|
||||
| `(Ansatz)` | 1 | ? |
|
||||
| `-psp` | 1 | ? |
|
||||
| `!Niereninsuffizienz!` | 1 | ? |
|
||||
| `+09.07.2017` | 1 | ? |
|
||||
| `7+09.07.2017` | 1 | ? |
|
||||
| `+2018` | 1 | ? |
|
||||
| `/05.06.2014` | 1 | ? |
|
||||
| `AAA` | 1 | ? |
|
||||
| `chmchm` | 1 | Schreibweise (c[chm]c[chm]) |
|
||||
| `c[chm]chm]` | 1 | ? |
|
||||
|
||||
627
tools/import/remaining.md
Normal file
627
tools/import/remaining.md
Normal file
@@ -0,0 +1,627 @@
|
||||
### Kuke | id=21ce7734-5c14-4212-b859-4bab330cd033 | Open | g=e4898ccc-1896-5258-b1a9-4c89d30cf428 l=None c=None
|
||||
MSG:Korrigiere ihre Daten als Schwarz Schecke
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Kuke | id=a50116bf-7b0b-432c-947d-4d1a8d5ce21e | Open | g=e4898ccc-1896-5258-b1a9-4c89d30cf428 l=None c=None
|
||||
MSG:Kuke hat die selben Nachzuchten, wie Blacky. Zu Blacky habe ich bereits ein Ticket erstellt, bitte korrigiere es! Auch fehlt ihr ihr Todes Tag und weitere Daten, bitte übernehme alle Daten von ihr aus
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Gaida von den Kleinen Chaoten | id=5df17f09-6863-43e3-b443-231cf2b57903 | Open | g=04358c1f-83ce-5082-bbf6-649cc1e7d81d l=None c=None
|
||||
MSG:Abgabedatum von Gaida: 05.01.2025
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Merle | id=a8f11ac0-fc1e-4cd1-894e-8bd8be984171 | Open | g=ce05fad7-496a-53eb-b03e-af92d90efaad l=None c=None
|
||||
MSG:Merle stammt von " Clan of Black Forest". Bitte überprüfe ihre Daten aus dem Stammbaum Excel "Pukas Kids". Sie wurde mit ihrer Tochter namens Speedy (Todestag: 18.08.2025, Ursache: unbelannt, lag tot
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Elena | id=ddc04a28-0d52-4552-8be7-3e4d135d7266 | Open | g=bc2400c9-0c9e-5aa8-9489-c1016223a1e0 l=None c=None
|
||||
MSG:Sie stammt von "Clan of KK Chaos". Bitte schau in RennerPro nach ihren Daten und anhand der Excel Wurfchronik, kannst du alle ihre Zuchtpartner und Würfe finden
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Sakura | id=7f9b3724-e237-4bf3-8027-42e77da62be3 | Open | g=f9ba065c-dfb7-5c0f-bbf6-0d3c2e4afed9 l=None c=None
|
||||
MSG:Bitte überprüfe die Rennerpro Daten. Die Herkunft ist Clan of little Angels
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Julien | id=2dbca1ae-a265-432f-afa5-df91ea0b6aa0 | Open | g=b78159a5-cc36-5651-9596-64adea21eebe l=None c=None
|
||||
MSG:Er hatte nie einen Wurf bei mir oder wo anders
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Targa | id=1500f0cc-793e-42d1-943a-d1f9539cf034 | Open | g=e9da5e4b-4f10-5e18-93fb-b625c8ca982d l=None c=None
|
||||
MSG:Targa ist meine Nachzucht. Sie wurde mit ihrer Tochter (Name: Druna, Farbe: Silberagouti, Todestag: 29.07.2024 Grund: Tumor im Bauchraum (Magen und Leber) an Nicole Nuzzo abgegeben. Sie starb dort am
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Shelly | id=c702498e-2239-452e-8622-fa110bbe7ff8 | Open | g=c470a68b-4cb2-5716-b67f-f63e49288dcb l=None c=None
|
||||
MSG:Bitte überprüfe seine Daten in RennerPro, da habe es wegen dem Namen schon ein Ticket, füge beide Tickets zusammen. Er ist auch verstorben
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Stacy | id=6b676f17-025f-4732-b804-8d64c3e54be0 | Open | g=14d5826c-0df0-5974-8ea1-fca5e224f3ed l=None c=None
|
||||
MSG:Sie ist auch verstorben
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Stacy | id=f8d55b7a-2008-442f-aaea-6243230422ef | Open | g=14d5826c-0df0-5974-8ea1-fca5e224f3ed l=None c=None
|
||||
MSG:Da fehlen ihre Daten. Bitte schau in RennerPro nach!
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Yumi | id=3fff5528-6fc9-4068-be27-19db25409e37 | Open | g=0cdd9624-461f-55a3-8432-cc99bb23c06c l=None c=None
|
||||
MSG:Vergleiche die Daten mit Rennerpro, hier fehlen einige! Sie ist auch verstorben
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Jamie | id=06b6734d-aa83-4026-9193-425a0508e03c | Open | g=05451eb1-cf16-5c6c-9f53-3b5ede5256b3 l=None c=None
|
||||
MSG:Bitte schau dir die Rennerpro Daten an. Da findest du Jamie und übernehme seine Daten
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Jamie | id=c092f8d2-b25c-4375-b13d-c0728c4a4711 | Open | g=05451eb1-cf16-5c6c-9f53-3b5ede5256b3 l=None c=None
|
||||
MSG:Das ist der Sohn von Danny von Privatzucht Maintal und Jana of little longnoses. Er stammt aus dem J-Wurf
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Jana | id=bd351aa2-5594-4ef2-8afc-a3db9a878521 | Open | g=b45e49e7-c222-535a-b4a5-9f15c0f180ae l=None c=None
|
||||
MSG:Hier steht, dass ihr Sohn Feivel in der Zucht war. Dass stimmt aber nicht. Feivel von Blacky und Kukes war in der Zucht. Dieser Feivel nicht!
|
||||
Nur ihr Sohn Jamie war in der Zucht!
|
||||
|
||||
Janas Herkunft ist:
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### P-Wurf | id=76d19fb2-11a5-440c-adc6-ab9bda1e30fa | Open | g=None l=c0eced1d-0d52-5ab5-82c1-874b73ccf259 c=None
|
||||
MSG:Bitte vergleiche diese Daten mit den Rennerpro Daten !
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### N-Wurf | id=a9841b10-2845-49b7-89e9-5f8611c31f5d | Open | g=None l=f26ee3f7-9f5f-5e85-9dd4-512b5ae4a810 c=None
|
||||
MSG:Was steht im Rennerpro, bitte vergleiche die Daten mit den Rennerpro Daten
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Glen | id=99fd58fb-a0cd-4be4-abfa-de57fb651694 | Open | g=d160e1c3-f4fb-551f-a755-366787761e73 l=None c=None
|
||||
MSG:Falsche Farbe , bitte in RennerPro nachschauen
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Gino | id=aefc3031-d4ab-41cb-8579-93b523d23f11 | Open | g=e3791a14-b560-5868-89ce-0b2feca10571 l=None c=None
|
||||
MSG:Falsche Farbe!! Bitte überprüfe es, in RennerPro muss es stehen. Ebenfalls habe ich Gino als Zuchttier verkauft, aber er ist dort zu früh verstorben, sodass er nie als Zuchttier eingesetzt wurde. Desh
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Galia | id=3607f345-e477-4aaf-8136-4ec1c9e169ff | Open | g=3d275ed7-2912-511c-b459-004fd2ae2786 l=None c=None
|
||||
MSG:Falsche Farbe!!! Bitte überprüfe es in der handgeschrieben Wurfchronik
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### J-Wurf | id=bfdb50fc-ce36-413e-83eb-3d70684a1563 | Open | g=None l=88cb68a5-f87e-5814-9541-d23742b08379 c=None
|
||||
MSG:Hier fehlt Jamie als Nachzucht im Wurf. Er war ein Zobel und ist ein mein Zuchttier gewesen und ahhte Würfe. Welche Würfe Jamie hatte , kannst du bitte in der Excel Wurfchronik schauen.
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Raya v.d. bunten Fellnasen | id=f56fa6d5-b8b6-4d11-85eb-d3e7f16338fd | Open | g=c59600dc-1eaa-54c0-b4e9-544fa409e639 l=None c=None
|
||||
MSG:Schau mal in RennerPro nach
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Raya v.d. bunten Fellnasen | id=1f9b4aad-81df-453a-926e-4dfdfdc12a5f | Open | g=c59600dc-1eaa-54c0-b4e9-544fa409e639 l=None c=None
|
||||
MSG:Raya ist verstorben
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### N5-Wurf | id=6898ec4f-cbfb-4651-a2c9-dc76b6ce5ed9 | Open | g=None l=3a7879a4-3cf0-5198-84ee-8e9085a8d43a c=None
|
||||
MSG:In der Suchfunktion kann man den N-Wurf nicht finden
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### H-Wurf | id=c68f152c-60b7-4c50-b812-05574a741f0f | Open | g=None l=fb78ff12-1781-5ad1-b2c4-951a61a9cece c=None
|
||||
MSG:Brauche eine Kategorie nach Jahren, wo man die Würfe finden oder nach Alphabet A-Z, A1-Z1, etc
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Benny von den Kleinen Chaoten | id=fbfac4b4-b1f0-4214-b2e4-da61f0d60696 | Open | g=3528d7be-56f7-5c2b-b773-f5bef00b2d0a l=None c=None
|
||||
MSG:Hatte einen Zuchteinsatz bei mir, bitte eintragen
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### F2-Wurf | id=33570213-8eda-4ac4-a1d7-6f5ef12f4ad6 | Open | g=None l=581fb310-9664-5acd-b2cb-6c3cc8ea15d6 c=None
|
||||
MSG:Der Vater ist bekannt, bitte auch in der Excel Wurfchronik
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Quentin gen. Eddy | id=ab34b1ba-31d0-4145-a370-024c18ef54f9 | Open | g=d4f0f1f8-2f99-5b6d-a4cf-69b45d38ed7b l=None c=None
|
||||
MSG:Warum steht zweimal Altersschwäche da?
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Quentin gen. Eddy | id=395667eb-5303-4823-8ebb-6259ceaf2b5a | Open | g=d4f0f1f8-2f99-5b6d-a4cf-69b45d38ed7b l=None c=None
|
||||
MSG:Der Farbschlag ist Kohlfuchsschimmel, hell
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Quvin | id=0b397a2c-8b8c-4344-9e88-f076ff8bfa80 | Open | g=efce9916-6634-5d38-b957-232fbc2dddae l=None c=None
|
||||
MSG:Man kann den Sterbegrund nicht komplett lesbar,bitte korrigiere das bzw füge das mehr Platz ein, damit man es lesen kann
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Malina of minor diabolus | id=b5d3eeba-96f9-44f7-9934-b5a53728cdcd | Open | g=35a174ed-c08e-5f38-b941-b5f7794b4313 l=None c=None
|
||||
MSG:Lexy, ihre Nachzucht, war nie in der Zucht. Ihr und Alvins Sohn Lee war in der Zucht
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Jana | id=4e7e86bc-c7fc-498b-be5a-1cf019a5768e | Answered | g=b45e49e7-c222-535a-b4a5-9f15c0f180ae l=None c=None
|
||||
MSG:Janas Herkunft: Clan of little Longnoses. Bitte übernehme ihre Daten aus Rennerpro. Sie war die Zuchtpartnerin von Danny und Flori
|
||||
A:Sind auch ihre Eltern übernommen worden? Bzw ihr ganzer Stammbaum?
|
||||
CTX:TRIAGE Jana (gerbilId b45e49e7-c222-535a-b4a5-9f15c0f180ae). Wunsch: Janas Daten aus RennmausPro übernehmen, Herkunft = Clan of little Longnoses.
|
||||
|
||||
BEFUND App-Record: name Jana, DateOfBirth=null, Gender=weiblich (Provenance), OriginBreeder=Unknown, ColorVarietyId=null, Genotype=nu
|
||||
|
||||
### C-Wurf 2010 | id=399dbeb2-6909-43fe-b00f-7b6a2b9fc7b2 | Answered | g=None l=f1fece40-f31a-5757-b89c-402fa47abbd4 c=None
|
||||
MSG:Die Jungtiere Reihenfolge ist die falsche. Es wird nicht nach Alphabet geordnet, sondern nach Geburtengewicht. Bitte korrigiere es anhand der Wurfchronik
|
||||
A:Genau.
|
||||
CTX:BEFUND: WurfDetailPage.tsx Z.86 laedt Jungtiere mit orderBy:'name' -> rein alphabetisch (C-Wurf 2010 f1fece40: Charlie, Chris, Dante). Zuechterin will 'anhand der Wurfchronik' sortieren. Wurfchronik-Quelle (Wurfchronik Teil 1_page_0013.md, 'Abzugebene Renner aus d. Wuerfen 2010')
|
||||
|
||||
### Z-Wurf | id=f42b6215-0896-4352-ae24-572829e6b42e | Open | g=None l=bad3a320-01ac-5b21-aa36-fd304891927b c=None
|
||||
MSG:Das ist die falsche Mutter. Bitte überprüfe es anhand der Wurfchroniken. Zeig mir ein Bild von dem Wurf aus der Wurfchronik
|
||||
A:
|
||||
CTX:BEFUND (Z-Wurf, litter bad3a320-01ac-5b21-aa36-fd304891927b, *27.01.2012, Quelle Wurfchronik Teil 1_page_0017.md): Angezeigte Mutter = synthetisches Wurfchronik-Tier "Macy" (516752f8-d9b1-5610-a215-75191f501ed0). Der Original-Scan (C:/Users/gulum/dev/Wurfchronik_Bilder/Wurfchroni
|
||||
|
||||
### N-Wurf | id=97a3b4d9-4859-4b0a-8e20-2c602ec2c167 | Answered | g=None l=f26ee3f7-9f5f-5e85-9dd4-512b5ae4a810 c=None
|
||||
MSG:Zeig mir bitte mal ein Foto von diesem Wurf aus der Wurfchronik
|
||||
A:Rennerpro 3 Backup hat doch die Bilder
|
||||
CTX:TRIAGE (Foto/Anzeige): Wunsch = Foto des N-Wurfs (litterId f26ee3f7-9f5f-5e85-9dd4-512b5ae4a810, *28.03.2011, WS 5) aus der Wurfchronik anzeigen. Befund: (1) Litter-Modell hat KEIN Foto-Feld (GerbilManagerWebAPI/Models/Litter.cs), keine Foto-Route in LitterEndpoints; Fotos existi
|
||||
|
||||
### Dante | id=9af81ae2-464c-480b-8199-6f73fcda8619 | Answered | g=93457716-65d2-5432-a52a-553ae873ca6d l=None c=None
|
||||
MSG:Bevor Dante abgegeben worde, hatte er einen Wurf bei mir
|
||||
A:Es geht darum, dass er nicht als Zuchttier (verstorben) in der Suche auftaucht. Auch wird er bei Danny, seinem Vater nicht als Nachzucht in der Zucht
|
||||
CTX:BEFUND: Ticket-Dante = gerbilId 93457716-65d2-5432-a52a-553ae873ca6d (Wurfchronik Teil 1_page_0013.md), isResident=true, Deceased, notes "CP-SA; → Jennifer Radtke; † Kokzidien 19.08.2011". Er HAT bereits einen Wurf als Vater: Q-Wurf litterId eb8047f2-c234-512b-b719-fe6ac6610d9c,
|
||||
|
||||
### Danny von Maintaler PZ | id=8e402d22-f5cb-4993-af05-cfab8c62ccb2 | Open | g=55ce13fc-0c90-5554-bf5a-f13c92ab9602 l=None c=None
|
||||
MSG:Bei Blacky und Flori hat die Verlinkung der Nachzuchten auch nicht funktioniert
|
||||
A:
|
||||
CTX:TRIAGE (companion zu 20a6cc0e "Warum funktionieren die Verlinkungen bei den Nachzuchten nicht?" - gleiche gerbilId Danny 55ce13fc, gleiche Seite gerbil-detail; verwandt: b7fbdb94 Flori/Feivel, 6f521e7c "zwei Danny mergen", rpro3-Dubletten 3272ddc4 "Blacky 5 Varianten").
|
||||
|
||||
Symptom
|
||||
|
||||
### Danny von Maintaler PZ | id=20a6cc0e-3798-4f3c-8452-efb32ce6dc84 | Open | g=55ce13fc-0c90-5554-bf5a-f13c92ab9602 l=None c=None
|
||||
MSG:Warum funktionieren die Verlinkungen bei den Nachzuchten nicht?
|
||||
A:
|
||||
CTX:BEFUND: Danny von Maintaler PZ (55ce13fc-0c90-5554-bf5a-f13c92ab9602) hat 3 Wuerfe (G-, J-, C-Wurf 2010) mit Nachzucht. Die Beschwerde "Verlinkungen bei den Nachzuchten funktionieren nicht" bezieht sich auf die Sektion offspringInBreedingTitle ("Nachzuchten in Zucht") in GerbilDe
|
||||
|
||||
### E-Wurf 2010 | id=573aad81-157e-47fe-8693-c1a4b685222b | Open | g=None l=53b55c8c-2979-5f65-b922-d6331de28637 c=None
|
||||
MSG:Falsche Reihenfolge, richtige: Eliza , Eddy
|
||||
A:
|
||||
CTX:Befund: Wurf E-Wurf 2010 (litterId 53b55c8c-2979-5f65-b922-d6331de28637, dob 2010-08-20, WS=2). Zwei Jungtiere: Eddy von den Kleinen Chaoten (m, id 3dab2309-a239-5de7-b501-64d494044bdb) und Eliza (w, id 29cbd5e6-cf4a-5cf5-9f50-5f85b752eec9), beide DOB 2010-08-20. Ursache: WurfDet
|
||||
|
||||
### F-Wurf 2010 | id=fa73d0db-53b7-4cc5-ac2a-6cd72dafab4e | Open | g=None l=10ddf880-6160-5530-83f6-551721205e3a c=None
|
||||
MSG:Die Reihenfolge der Jungtiere stimmt nicht! Die richtige ist: Keks, Flori, Krümmel und Fiona
|
||||
A:
|
||||
CTX:BEFUND: Ticket betrifft F-Wurf 2010 (litter 10ddf880-6160-5530-83f6-551721205e3a, Blacky x Kruke, 21.09.2010, WS=4). Die 4 Jungtiere: Keks (651d6697, externalRef …g1000000-…-000012), Flori von den Kleinen Chaoten (90a37fe0, externalRef …-002010), Krümmel (38c6b3c9, …-000014), Fio
|
||||
|
||||
### O-Wurf | id=8ff0ebe6-159a-49ce-80ad-23c100c21056 | Open | g=None l=137e0cc7-6b25-5cf3-ad71-244bcbb7afe2 c=None
|
||||
MSG:Die Reihenfolge der Jungtiere stimmt nicht. Die richtige wäre: Olli, Felix, Momo, Foxi & Oki
|
||||
A:
|
||||
CTX:BEFUND (O-Wurf, litter 137e0cc7-6b25-5cf3-ad71-244bcbb7afe2, *2011-04-12, WS 5, Vater 9b40b9e5, Mutter=null):
|
||||
5 Jungtiere, alle DOB gleich. Aktuelle Anzeige-Reihenfolge = alphabetisch nach Name: Felix, Foxi, Momo, Oki, Olli. Gewuenscht (Zuechterin): Olli, Felix, Momo, Foxi, Oki.
|
||||
|
||||
### M-Wurf | id=7d032fc5-f6b8-4c72-891d-f87fc4935ac9 | Answered | g=None l=f5d543bb-0732-509c-849d-656694ec557e c=None
|
||||
MSG:Die Mutter heißt Charlett of little longnoses (*14.05.2010). Bitte überprüfe die Daten von Charlett aus Rennerpro.
|
||||
|
||||
Bitte übernehme auch die Daten von M Wurf und O Wurf komplett. Der M-Wurf ist hier u
|
||||
A:Bitte schau im RennerPro im M-Wurf nach, da stehen alle bei Blacky M-Wurf
|
||||
CTX:TRIAGE (handoff) — M-Wurf/O-Wurf: Mutter Charlett fehlt + M-Wurf unvollstaendig.
|
||||
|
||||
BEFUND:
|
||||
- M-Wurf (litter f5d543bb-0732-509c-849d-656694ec557e): date 2011-03-03, totalBorn 6 (notes "WS: 6 (5 Tiere notiert)"), Vater=Blacky von PZ Seligenstadt (9b40b9e5-a9d3-5d63-ae34-8105297a8b18
|
||||
|
||||
### Eddy von den Kleinen Chaoten | id=e5900a79-c21c-435d-af3e-9dc9518c5b40 | Open | g=3dab2309-a239-5de7-b501-64d494044bdb l=None c=None
|
||||
MSG:Hier fehlt die Nachzucht in der Zucht. Sein Sohn ist Oskar von den bunten Fellnasen. Dieser sollte unten auftauchen. Da Oskar mein Zuchttier war
|
||||
A:
|
||||
CTX:BEFUND: Eddy von den Kleinen Chaoten (3dab2309-a239-5de7-b501-64d494044bdb) ist isResident=false (externer/reiner Ahne). Sein Sohn Oskar von den bunten Fellnasen (f18246d8-b66c-50d6-8f12-992ffb37ea46, *13.06.2012, isResident=true) existiert korrekt und die Eltern-Verknuepfung ist
|
||||
|
||||
### Flori von den Kleinen Chaoten | id=b7fbdb94-202b-488b-ab5f-6a2b868e65e3 | Open | g=90a37fe0-551c-5ff1-9bd2-693a0adf0cf9 l=None c=None
|
||||
MSG:Bei Nachzuchten kann ich auf Feivel ist drücken. Was ist da los? Ich glaube, das Flori nur eine Nachzucht in der Zucht hatte und zwar JD. Aber bitte überprüfe es anhand der handgeschrieben Wurfchronik
|
||||
A:
|
||||
CTX:BEFUND: Doppelter "Feivel" – der Wurf-Vater wurde dem falschen Namensvetter zugeordnet.
|
||||
- Ticket-Tier (Detailseite): Feivel von den Kleinen Chaoten, id=be5bca76-e8f7-5452-ac78-30c96fae245b, DOB 2010-12-01, gestorben 25.10.2013, gender=male, isResident=False, KEINE Wuerfe -> desha
|
||||
|
||||
### Domi | id=ddacd093-b3f4-419f-911d-39ef9e746ae3 | Open | g=544b3c5c-8c40-59d6-8e41-d5f22a3869b2 l=None c=None
|
||||
MSG:Blacky und Kukes Nachkommen sollte alle Fotos und Rennerpro haben, übernehme diese bitte!
|
||||
A:
|
||||
CTX:TRIAGE ddacd093 (gerbil-detail, Domi 544b3c5c-8c40-59d6-8e41-d5f22a3869b2). Wunsch der Zuechterin: Alle Nachkommen von Blacky x Kuke sollen Fotos + RennmausPro-Daten (rpro3) bekommen -> rpro3-Uebernahme. == DB-Stand == Domi: weibl., DOB 2010-06-25, +2012-07-15, Genotyp aa CC DD E
|
||||
|
||||
### Dastan | id=0ebc250f-17a7-45d8-8b21-91e563fbfd9c | Open | g=fba979a3-2317-5d7c-b4f9-6e2f9cd74152 l=None c=None
|
||||
MSG:Dastan (Nachzucht von Blacky und Kuke) war nie in der Zucht. Du hast verschieden Dastan in der Datenbank. Dieser hier hat nichts mit den anderen zu tun. Er wurde als Liebhabertier (LH ist die Abkürzu
|
||||
A:
|
||||
CTX:TRIAGE Dastan (fba979a3-2317-5d7c-b4f9-6e2f9cd74152) — Import-Dedup ueber-merged ZWEI verschiedene Dastan zu einem Datensatz.
|
||||
|
||||
BEFUND (harter Beleg): Datensatz fba979a3 ist mergedRecordCount=6 (Provenance: Wurfchronik Teil1 p1/13/45/46/50 + Teil2 p6). Er ist zugleich (a) das Blac
|
||||
|
||||
### Bodo | id=aaee068b-16a8-46a7-b973-a06577cc5ab1 | Open | g=6c2f3c06-ab83-55cd-a584-d91e858c3ee8 l=None c=None
|
||||
MSG:Bei Herkunft bitte ändern in Zucht der Kleinen Chaoten. Bitte überall bei anderen Rennmäuse, wo Clan Kleine Chaoten als Herkunft steht in Zucht der Kleinen Chaoten abändern.
|
||||
A:
|
||||
CTX:BEFUND: Ticket betrifft Bodo (6c2f3c06-ab83-55cd-a584-d91e858c3ee8). Das UI-Feld "Herkunft" auf der Tier-Akte zeigt gerbil.originBreeder (GerbilDetailPage.tsx Z.507). Bei Bodo steht dort "Clan kleine Chaoten". Wunsch der Zuechterin: ueberall "Clan (kleine) Chaoten" als Herkunft -
|
||||
|
||||
### A-Wurf | id=a555dd0a-f693-487c-8c7f-db8e29b363f5 | Open | g=None l=29f4bae9-ca7d-56c4-b8bc-8283d5284b87 c=None
|
||||
MSG:Du kannst das vorraussichtliche Abgabedatum immer selbst errechnen:
|
||||
Zur Vergesellschaftung: Alter 8 Wochen( bitte darauf die Kalender Wochen abzählen)
|
||||
Abgabedatum als Gruppe: Alter 10 Wochen( bitte da
|
||||
A:
|
||||
CTX:BEFUND (litter-detail, A-Wurf 29f4bae9): Zuechterin praezisiert die Regel fuer das voraussichtliche Abgabedatum. Vergesellschaftung = Alter 8 Wochen (56 Tage nach Wurfdatum); Abgabe als Gruppe = Alter 10 Wochen (70 Tage). URSACHE: App schlaegt aktuell nur EIN Datum vor und rechne
|
||||
|
||||
### Alvin von den kleinen Chaoten | id=d1069edb-1001-4e24-b436-147948b85c8a | Answered | g=b04dc268-1b2e-588b-a2e1-e51bee0df871 l=None c=None
|
||||
MSG:Überprüfe bitte Alvins Nachkommen, die in der Zucht waren. Denn es sollte nur: Hero (Zuchteinsatz), Flippi (Zuchteinsatz), Gimli (Zuchteinsatz), Lee & Sam stehen dürfen.
|
||||
A:Genau, Lee und Sam hatten Würfe bei mir. Bitte schaue in der Excel Wurfchronik nach, welche Würfe sie hatten.
|
||||
Sunny, Zora, Lexy und Zorro hatten keine
|
||||
CTX:BEFUND: Akten-Sektion „offspringInBreedingTitle“ (GerbilDetailPage.tsx Z.673-701) listet Alvins Kinder, die entweder status==Breeding sind ODER als Vater/Mutter irgendeines Wurfs in listLitters() vorkommen (breedingParentIds, Z.101-126). Alle 20 Alvin-Kinder sind Deceased, also z
|
||||
|
||||
### Alvin von den kleinen Chaoten | id=72d18800-342b-4935-9aad-311a1607b3da | Answered | g=b04dc268-1b2e-588b-a2e1-e51bee0df871 l=None c=None
|
||||
MSG:Die Nachzucht von Alvin namens Hero hatte nur einen Zuchteinsatz bei mir!
|
||||
A:Hero wurde abgegeben. Zuchteinsatz bedeutet, dass das Tier für einen Zuchteinsatz mir ausgeliehen wurde und nach dem Wurf wieder an den Besitzer zurüc
|
||||
CTX:BEFUND: Hero (gerbilId 7f0d43cc-0cf6-5afc-98bd-63ab6f031c04) ist Sohn von Alvin (H-Wurf 7bc5be7d, *31.10.2010). In der Live-DB hat Hero GENAU EINEN Wurf als Vater: D3-Wurf (litter 421851c3-dedd-5620-80ec-a06e27c9cec9, 22.11.2013, Mutter Mira von den Kleinen Chaoten 49251fb7). Dam
|
||||
|
||||
### Blacky von PZ Seligenstadt | id=00493a79-b4e1-4856-b0c4-9e08508ca484 | Answered | g=9b40b9e5-a9d3-5d63-ae34-8105297a8b18 l=None c=None
|
||||
MSG:In den Rennerpro Daten solltest du auch Fotos von Blacky finden
|
||||
A:Da ist ein zweites ZIP neben dem echten Backup Dateien. Da sind die Bilder drinnen
|
||||
CTX:BEFUND: Blacky von PZ Seligenstadt (gerbilId 9b40b9e5-a9d3-5d63-ae34-8105297a8b18) hat in der App aktuell 0 Fotos (photos=[], profilePhotoUrl=null). Tier stammt laut Provenance aus Stammbaum-xlsx (Jin/Wildfire), NICHT aus rpro3. RPRO3-ABGLEICH: tools/import/_rpro3.db stamm_tb id=
|
||||
|
||||
### Blacky von PZ Seligenstadt | id=2bc311df-2f1e-400c-8fa0-2468cc9c9d9b | Open | g=9b40b9e5-a9d3-5d63-ae34-8105297a8b18 l=None c=None
|
||||
MSG:Übernehme die Gesundheitsdaten und Gewichte aus Renner pro
|
||||
A:
|
||||
CTX:BEFUND: Ticket auf gerbil-detail von 'Blacky von PZ Seligenstadt' (9b40b9e5-a9d3-5d63-ae34-8105297a8b18, externalRef stammbaum-*, externer Ahn *2009-07-23 +2011-07-13). Wunsch: Gesundheitsdaten + Gewichte aus RennmausPro (RennerPro) uebernehmen. QUELLE VORHANDEN: rpro3 stamm_tb i
|
||||
|
||||
### Blacky von PZ Seligenstadt | id=7dedec07-99b8-4b0c-9f51-bf14a583ec67 | Answered | g=9b40b9e5-a9d3-5d63-ae34-8105297a8b18 l=None c=None
|
||||
MSG:Bei Zuchttieren, die nicht aus meiner Zucht stammen sollte die Leiste mit dem Wurf nicht angezeigt werden!
|
||||
A:Blacky ist mein Zuchttier, dh ich habe mit ihm selbst gezüchtet, jedoch wird in seinem Stammdaten Satz die Leiste Wurf angezeigt. Da Blacky nicht aus
|
||||
CTX:BEFUND: Blacky von PZ Seligenstadt (gerbilId 9b40b9e5-a9d3-5d63-ae34-8105297a8b18) ist isResident=true, Status Deceased, maennl., *2009-07-23 +2011-07-13, originBreeder="Privatzucht Seligenstadt", nur aus Stammbaeumen (Jin; Wildfire und Vestras Kids), fromWurfchronik=false. Er is
|
||||
|
||||
### Blacky von PZ Seligenstadt | id=690946e6-714f-4816-b6b9-b76a5da6057a | Answered | g=9b40b9e5-a9d3-5d63-ae34-8105297a8b18 l=None c=None
|
||||
MSG:Bitte überprüfe die Nachzuchten von Blacky , die in der Zucht waren anhand der Excel Wurfchronik.
|
||||
Es sollten eigentlich nur Alvin, Eddy, Fiona, Flori und Feivel als seine Nachzuchten in der Zucht vork
|
||||
A:Dastan, Eliza, Ina, Ivy und Isa diese Tiere haben den selben Namen, wie andere Zuchttiere. Jedoch sind genau diese Tiere von Blacky nie in der Zucht e
|
||||
CTX:TRIAGE (Blacky von PZ Seligenstadt, gerbilId=9b40b9e5-a9d3-5d63-ae34-8105297a8b18).
|
||||
|
||||
BEFUND: Blacky ist im Import als Vater von 8 Wuerfen verknuepft (A,B,D,E,F,I,M,O) mit ~26 zugeordneten Kindern. Die Zuechterin sagt: nur 5 echte Nachzuchten in der Zucht: Alvin, Eddy, Fiona, Flor
|
||||
|
||||
### Blacky von PZ Seligenstadt | id=267474c8-bd1d-47e7-8c1f-4250ebfbf2cb | Open | g=9b40b9e5-a9d3-5d63-ae34-8105297a8b18 l=None c=None
|
||||
MSG:Die Daten von Erwerb bitte aus den Rennerpro Daten übernehmen. Sowie sein Todesdatum
|
||||
A:
|
||||
CTX:BEFUND: Blacky von PZ Seligenstadt (gerbilId 9b40b9e5-a9d3-5d63-ae34-8105297a8b18) ist Stammbaum-Import (externalRef stammbaum-blackypzseligenstadt-23072009, originBreeder "Privatzucht Seligenstadt", DOB 2009-07-23, isResident=true). Aktuell: dateOfDeath=2011-07-13 (Quelle "Stamm
|
||||
|
||||
### Nymphs | id=ca8a1c48-1407-44ed-908f-986cbc0e5e0b | NeedsInfo | g=f86ca53c-0474-56f5-8fb3-f490a7ef4e9e l=None c=None
|
||||
MSG:Wer ist das? Wo hat's du das wieder her?
|
||||
A:
|
||||
CTX:{"befund": "Gerbil f86ca53c „Nymphs\": sex=null (Provenance sagt männlich), DOB/color/genotype=null, motherId/fatherId/litterId=null, isResident=true, status=Breeding, notes \"Breeding male. Originally CP-Nymphs.\", externalRef \"Wurfchronik Teil 2_page_0026.md-8cf53a1a...\", Que
|
||||
|
||||
### Willow | id=9935323f-883e-4686-b3ff-de8d10de4722 | Open | g=3f9c5a26-af3a-55dc-9c4b-4ebdea4ce36f l=None c=None
|
||||
MSG:Das ist ein Weibchen! Bitte schau anhand ihres Geburtstags in der Wurfchronik Excel wer ihre Eltern sind
|
||||
A:
|
||||
CTX:BEFUND: Willow (id 3f9c5a26-af3a-55dc-9c4b-4ebdea4ce36f) in Live-DB: gender=male, dateOfBirth=None, litterId/motherId/fatherId=None, isResident=true, originBreeder="Zucht der kleinen Chaoten", importSource="Wurfchronik Teil 2_page_0006.md", externalRef …-89fca8be…. Provenance-His
|
||||
|
||||
### Tai | id=b222b459-57c5-40ea-88b0-0fa696869c6b | NeedsInfo | g=fe483a84-cd3c-5382-bba6-f7df7832cc3b l=None c=None
|
||||
MSG:Die Maus ist verstorben, bitte schau in RennerPro nach
|
||||
A:
|
||||
CTX:BEFUND: Ticket meldet Tai verstorben, bittet um RennerPro-Abgleich. App-Tier fe483a84-cd3c-5382-bba6-f7df7832cc3b (Tai) hat status=Breeding, dateOfDeath=null, dateOfBirth=null, aus Wurfchronik Teil1 p0021. RPRO3-ABGLEICH (_rpro3.db, Backup 27.06.): stamm_tb id=38 "Tai gen. Karlch
|
||||
|
||||
### Dusty | id=034b4988-5447-4c54-ad28-9a6708133517 | Answered | g=41d7577e-bcaf-5967-a6ed-fe0b52171f77 l=None c=None
|
||||
MSG:Stammbaum fehlt! Und wer sind seine Nachkommen
|
||||
A:Dusty von Mira und Hero war nie in der Zucht.
|
||||
Dusty of golden lights ist der Bock
|
||||
CTX:BEFUND: Ticket-Tier = maennlicher Zuchtbock Dusty (41d7577e-bcaf-5967-a6ed-fe0b52171f77), importSource Wurfchronik page_0050, KEIN Geburtsdatum, KEINE Eltern/litterId => Stammbaum (Ahnen) leer. Nachkommen existieren jedoch: 3 Wuerfe in DB (P6-Wurf, Dusty+Harumi 29.06.15, A-Sp-Wur
|
||||
|
||||
### Drake Jr | id=31811914-257b-4c83-bb42-85cc2d140277 | NeedsInfo | g=7f09dd7b-58f3-5b5c-8feb-888b2ebe4d16 l=None c=None
|
||||
MSG:Stammbaum fehlt. Hat das Tier einen Wurf gezeugt?
|
||||
A:
|
||||
CTX:BEFUND: Drake Jr (7f09dd7b-58f3-5b5c-8feb-888b2ebe4d16), maennlich, resident=true, litterId=null -> keine Eltern -> Ahnenbaum zeigt nur Platzhalter (build.ts: Gruendertier ohne litterId => unknown father/mother), daher "Stammbaum fehlt". Zur Frage der Zuechterin: JA, er ist Vater
|
||||
|
||||
### Fast Boy of Golden Lights | id=0e139f1f-8aa7-4705-a430-0985cf9aa625 | NeedsInfo | g=509f4aae-1189-585c-b410-555e75d5d907 l=None c=None
|
||||
MSG:Stammbaum unvollständig. Den findest du in den Rennerpro Daten
|
||||
A:
|
||||
CTX:BEFUND (Ticket 740360e5, Katinka of little runner's, b66c6e06-7457-5768-a5f3-1dae9579eb44):
|
||||
- App-Record stammt aus Excel-Stammbaum "Stammbaum von little Heros Sohn of little runners.xlsx" (externalRef stammbaum-katinkalittlerunners), weiblich, isResident=false (externer Ahn, kor
|
||||
|
||||
### Chiko | id=bc859109-32df-4506-9f7d-6f6415c00f02 | Answered | g=7d3b7c47-6320-5181-b612-56676e4516d5 l=None c=None
|
||||
MSG:Stammbaum? Wer ist das
|
||||
A:Steht der Name Chiko in keiner meiner Würfe in der handgeschrieben Wurfchronik?
|
||||
CTX:BEFUND: Chiko (7d3b7c47-6320-5181-b612-56676e4516d5) ist ein reiner Wurfchronik-Parent. Quelle: Wurfchronik Teil 2_page_0035.md. gender=male, isResident=true (weil Vater eines eigenen Wurfs), status=Breeding. KEINE Eltern (litterId=null) -> leerer Stammbaum; kein DOB, kein genoty
|
||||
|
||||
### Aaren | id=7a9831f6-4d68-41e7-add2-bc06393e6ed6 | Answered | g=d60133c6-cc1c-584a-8bbc-cd177318b386 l=None c=None
|
||||
MSG:Wo ist der Stammbaum?
|
||||
A:In jedem Kaufvertrags Namen stehen oben in Klammern die Eltern . Schau bitte nach. (Diese Regel gilt immer, mit Ausnahme in Dateinamem stehen keine Kl
|
||||
CTX:Ticket 7a9831f6: "Wo ist der Stammbaum?" fuer Aaren (d60133c6-cc1c-584a-8bbc-cd177318b386). Befund: Aaren ist manuell ueber conflict-decisions.json addAnimals (externalRef decision-aaren, Ticket ad50175c, Kaufvertrag-Screenshot) angelegt; fatherId=None, motherId=None, litterId=No
|
||||
|
||||
### Katinka of little runner's | id=740360e5-151d-4dca-a596-f71bc128771b | Open | g=b66c6e06-7457-5768-a5f3-1dae9579eb44 l=None c=None
|
||||
MSG:Der Stammbaum stimmt nicht!!
|
||||
|
||||
Du hast Daten aus den Excel Tabelle und von Rennerpro, du musst die auch verknüpfen
|
||||
A:
|
||||
CTX:BEFUND (Ticket 740360e5, Katinka of little runner's, b66c6e06-7457-5768-a5f3-1dae9579eb44):
|
||||
- App-Record stammt aus Excel-Stammbaum "Stammbaum von little Heros Sohn of little runners.xlsx" (externalRef stammbaum-katinkalittlerunners), weiblich, isResident=false (externer Ahn, kor
|
||||
|
||||
### Percy of little runners | id=e87a6da5-0ff1-46b6-b4ec-5d05a1605f5f | NeedsInfo | g=b27696ad-8866-50a8-a315-36176be69198 l=None c=None
|
||||
MSG:Warum ist die Mutter unbekannt? Die ist bekannt
|
||||
A:
|
||||
CTX:Befund: /gerbils/b27696ad Percy of little runners (percylittlerunners-16122017, extern/non-resident) hat motherId=fatherId=null. Ursache in output/animals.json parentRefs: chart-position-Heuristik lieferte 3 Kandidaten: Rasputin of little runner's (09.03.2017, roleGuess father, p
|
||||
|
||||
### Percy of little runners | id=e04ceda2-1701-4820-b21f-376dc6d0c5d1 | Open | g=b27696ad-8866-50a8-a315-36176be69198 l=None c=None
|
||||
MSG:Das Foto ist falsch bei der Farbe. Da sollte ein schwarz Schecke und kein schwarz auf dem Foto zu sehen sein
|
||||
A:
|
||||
CTX:BEFUND (Triage, gerbil-detail): Tier "Percy of little runners" id=b27696ad-8866-50a8-a315-36176be69198, isResident=false (extern), genotype=aa Cc[chm] DD Ee Gg Pp Spsp -> Sp-Locus heterozygot => Schecke. colorVarietyId=00000000-...-0007 = Basis "Schwarz". formatVarietyName(Schwar
|
||||
|
||||
### Blue | id=6c5c2678-8b19-4bd3-8ea8-f20eed0c66ad | NeedsInfo | g=42b78689-50d7-52e3-8dd2-f961cc55a4ee l=None c=None
|
||||
MSG:Wieso gibt es drei Mal Blue? ITS das nicht alles der selbe?
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Belica gen. Emi von den Kleinen Chaoten | id=23ed08d8-345a-472f-892d-76d07ded7d74 | NeedsInfo | g=e94dac93-ad99-52a3-9cbe-b5ccf2cd5375 l=None c=None
|
||||
MSG:Suche das Sterbedatum heraus
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### F-Wurf 2010 | id=21c8ff24-cc03-4508-b6c6-849ab36ba5b2 | NeedsInfo | g=None l=10ddf880-6160-5530-83f6-551721205e3a c=None
|
||||
MSG:Warum ist bei Krümel kein Todesdatum?
|
||||
A:
|
||||
CTX:TRIAGE (litter-detail, F-Wurf 2010, litter 10ddf880-6160-5530-83f6-551721205e3a). Frage: warum kein Todesdatum bei Krümmel. Befund: Krümmel gerbilId=38c6b3c9-18ca-530f-8657-02d62e7c0e59, dob 2010-09-21, dateOfDeath=null, causeOfDeath=null. Geschwister (Fiona 2f5ed952, Keks 651d66
|
||||
|
||||
### N | id=c247217d-267d-4d45-b3e3-00a094941f53 | NeedsInfo | g=2655db59-bc8a-519c-940b-5c1ea295a4ce l=None c=None
|
||||
MSG:N? Woher hat's du diese Daten?
|
||||
A:
|
||||
CTX:Ticket c247217d: Tier 'N' (gerbilId 2655db59-bc8a-519c-940b-5c1ea295a4ce). Befund: name=='N' stammt 1:1 aus der Namensspalte (col 2) der Wurfchronik (extract_docx.py:188). externalRef=docx-106-n-2022-11-05, importSource=Wurfchronik-Detail.docx, DOB 2022-11-05, female, status Bree
|
||||
|
||||
### Elfenbein-Apricot-Sp | id=1f56d211-5635-4c38-bc67-546279dabfa8 | NeedsInfo | g=6377de21-2a06-56b2-83c1-99fb6eb79c8b l=None c=None
|
||||
MSG:Wer ist das? Ich kenne das Tier nicht, da fehlen alle Daten
|
||||
A:
|
||||
CTX:Ticket 1f56d211 (gerbil-detail). Gerbil 6377de21-2a06-56b2-83c1-99fb6eb79c8b name='Elfenbein-Apricot-Sp' (male, status Breeding, isResident=true, ALLE Felder NULL, notes 'Parent of Litter 6'). Phantom/Karteileiche: 'Name' ist eine Farb-Beschreibung. Quelle Wurfchronik-Teil-2 page
|
||||
|
||||
### y | id=7cdb062d-c8be-428e-a281-5617b933ca16 | NeedsInfo | g=1b556d4d-f05b-528f-b868-ab3f92192342 l=None c=None
|
||||
MSG:Das selbe Problem, wie beim Tierarzt "Y".
|
||||
A:
|
||||
CTX:TRIAGE 2026-06-27 Ticket 7cdb062d (entityName 'y', gerbilId 1b556d4d-f05b-528f-b868-ab3f92192342). KLASSE: import-data (Wurfchronik-Extraktion), identisch zu M-Ticket bd84256b und N-Ticket c247217d. BEFUND: ZWEI Platzhalter-Tiere im selben Wurf Y21-Wurf (litter 18778607-b987-5396
|
||||
|
||||
### Y | id=591172f3-341f-4eeb-b0ab-a04910ceaf37 | NeedsInfo | g=974c1589-b7b9-5a28-b25c-4752c2a93899 l=None c=None
|
||||
MSG:Wer ist das? Wieso fehlt der Stammbaum? Wieso ist es ein Zuchttier von mir?
|
||||
A:
|
||||
CTX:TICKET 591172f3 [gerbil-detail / placeholder-name + missing-pedigree + wrong-status]. Tier: Y (974c1589-b7b9-5a28-b25c-4752c2a93899), w, Anthrazit (colorVariety ...0009), DOB 2023-01-21, status=Breeding, isResident=false (Sweep bereits korrekt), importSource Wurfchronik-Detail.do
|
||||
|
||||
### Donny | id=3a4fd3c8-ab45-4bcf-b7bb-118f44f2529a | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Donny" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:rpro3 Donny: 2 Varianten (A=Schwarz-Schecke u1240 2x, B=Schwarz u990 1x), beide DOB 2008-02-11, Eltern Chango+Paula, Herkunft Clan of Happy Mice. Gencode beider identisch (aa CC DD Ee Gg Pp Spsp). Geliefert: Partner+Nachzucht beider Varianten; Herkunft aller verwandten Tiere (kei
|
||||
|
||||
### Lukas | id=422f5c3f-b6f2-40e8-9b0e-a396cbe4a5f1 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Lukas" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:rpro3 Lukas (2 Varianten, beide externer Ahn). A=u557 (DOB 2005-11-14, Anthrazit, Herkunft unbekannt), B=u1441 (DOB 2005-11-14, Marder-Hell-Schecke, Herkunft Laura Gerber).
|
||||
Runde 4 (2026-06-27): Zuechterin bat um Gencode/Nachzucht/Partner BEIDER Tessy (Lukas-Kinder). Aus _rpro3.d
|
||||
|
||||
### Dunny | id=035ee655-d354-4e90-949a-16921c77ab64 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Dunny" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:rpro3 Dunny (2 Var, beide *2005-06-18): A=u556 Zobel-Hell (Eltern unbek.), B=u1445 Marder-Hell-Schecke (Eltern Suntie+Sissy). R3: Frage 'in welchem Stammbaum' beantwortet -> Dunny/Dana/Umfeld NICHT in Live-App (0 Treffer, nur unverwandte Vandana/Danako). Warte weiter auf same/dif
|
||||
|
||||
### Nunny | id=4b38b3d6-3597-4f3e-9aa6-ae32babc0934 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Nunny" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:rpro3 Nunny (2 Var, beide *2005-09-06, Partner Dunny, Kind Dana): A=u555 Marder-Schecke (aa c[chm]c[chm] DD E- Gg PP Spsp, Eltern unbek.), B=u1442 Zobel-Schecke (aa c[chm]c[chm] DD E- gg PP Spsp, Eltern Hannes=Agouti-Schecke Aa Cc[chm] DD Ee Gg PP Spsp / Hanny=Zobel aa c[chm]c[ch
|
||||
|
||||
### Tessy | id=2530bf41-bf4d-42a3-a291-bc8f8100e051 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Tessy" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Tessy", "variants": [{"label": "A", "rids": ["u1439", "u1455"], "count": 2, "dob": ["2006-05-24"], "farbe": ["Marder-Hell-Schecke"], "origin": ["Baru of Lienehma"], "is_own": false, "matched_gerbil_id": null, "vater": "Lukas (Marder-Hell-Sch
|
||||
|
||||
### Bubi | id=945143e4-d219-4bf0-8a8f-91d04b1ad94e | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Bubi" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Bubi", "variants": [{"label": "A", "rids": ["u115"], "count": 1, "dob": ["2007-04-18"], "farbe": ["Zobel-Schecke"], "origin": ["Clan of Tamyna"], "is_own": false, "matched_gerbil_id": null, "gencode": "aa c[chm]c[chm] DD Ee gg P- Spsp", "par
|
||||
|
||||
### Speedy | id=bedb4017-0499-4a50-b2a4-32544601636c | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Speedy" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"ticket":"bedb4017 Speedy rpro3-ambiguity","breeder_answer":"Alle verschieden + Folgefrage: ist B als ehemaliges (verstorbenes) Zuchttier hinterlegt?","decision":"Alle 3 verschieden -> KEIN rpro3 same/different noetig; A/B/C trennen automatisch ueber DOB+Farbe. A=u706/u2883/u677
|
||||
|
||||
### Dana | id=e670ca2f-7203-4653-876c-d4c93706999b | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Dana" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Dana", "variants": [{"label": "A", "rids": ["u554"], "count": 1, "dob": ["2006-01-16"], "farbe": ["Colourpoint-Silberagouti-Schecke"], "origin": [], "is_own": false, "matched_gerbil_id": null}, {"label": "B", "rids": ["u1440"], "count": 1, "
|
||||
|
||||
### Sina | id=cd4b24b0-7b48-4fcf-880d-6f86f12755d9 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Sina" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:rpro3 Sina: 3 Varianten (Ticket-Buchstaben). Ticket A=Marder-Hell geb.2005-12-28 Herkunft unbekannt = Lookup-Block B (Gencode aa c[chm]c[h] DD Ee G- P- spsp; Eltern unbekannt; Partner Sam; Nachzucht Nany, Cassie). Ticket B=Marder-Schecke geb.2005-12-28 Clan of Letter Live = Looku
|
||||
|
||||
### Anton | id=33af41eb-ffac-47bc-8467-561dba513c06 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Anton" kommt mehrfach vor (5 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source":"rpro3-ambiguity","name":"Anton","stage":"Züchterin entschied: A&B=same, C&D&E=same; bat zusätzlich Nachzucht zu mergen + Inkonsistenzen zu melden. Rückfrage gestellt wg. DOB/Farb-Inkonsistenzen in C/D/E und in den Kindern Romina/Bärchen sowie Blackeye-Großcluster.","br
|
||||
|
||||
### Pünktchen | id=12440e00-829e-4209-b3d9-a3d28e7879e7 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Pünktchen" kommt mehrfach vor (5 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Pünktchen", "status": "awaiting-merge-decision", "delivered": "Pro Variante A-E: DOB, Farbe, Gencode, Herkunft, Eltern, Nachzucht+Partner geliefert (Antwort auf Bitte um Eltern/Nachzucht/Partner/Farben/Gencodes).", "hints_given": ["A & B tei
|
||||
|
||||
### Paula | id=5931f460-b39d-4ab4-913b-c29f18df0f13 | NeedsInfo | g=b41c3686-67a3-5e01-9201-347622ade9d7 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Paula" kommt mehrfach vor (5 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Paula", "variants": [{"label": "A", "rids": ["u1241", "u6865"], "count": 2, "dob": ["2007-08-25"], "farbe": ["Anthrazit-Schecke"], "origin": [], "is_own": false, "matched_gerbil_id": "b41c3686-67a3-5e01-9201-347622ade9d7"}, {"label": "B", "r
|
||||
|
||||
### John | id=95785340-fa25-4e74-b0fc-36f9a3826e56 | NeedsInfo | g=340542b7-c573-5e25-9964-0677f4c45be8 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „John" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "John", "variants": [{"label": "A", "rids": ["295"], "count": 1, "dob": ["2018-02-19"], "farbe": ["Polarfuchs"], "origin": ["Kleinen Chaoten"], "is_own": true, "matched_gerbil_id": "340542b7-c573-5e25-9964-0677f4c45be8"}, {"label": "B", "rids
|
||||
|
||||
### Enya | id=351f931a-27dd-4376-837c-5a780e379af1 | NeedsInfo | g=2b22b29e-905e-5ccd-aeee-44eee0b825b2 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Enya" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Enya", "variants": [{"label": "A", "rids": ["286"], "count": 1, "dob": ["2017-11-01"], "farbe": ["Colourpoint-Fuchs"], "origin": ["Kleinen Chaoten"], "is_own": true, "matched_gerbil_id": "2b22b29e-905e-5ccd-aeee-44eee0b825b2"}, {"label": "B"
|
||||
|
||||
### Nancy | id=e74e1fab-515b-4296-9161-7b0d6f4be382 | NeedsInfo | g=2a5e6d88-9b8d-5371-b0d5-b6cdc3bfc787 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Nancy" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Nancy", "round": 2, "decision": "Zuechterin: 'alle verschieden'. Nancy A (rid 279, 2014-05-18, Agouti, Annemarie Knief1, eigenes/Vorfahre) und Nancy B (rid u6443, 2014-04-20, Agouti-Schecke, Kleinen Chaoten) sind VERSCHIEDENE Tiere -> getren
|
||||
|
||||
### Max | id=625a86ab-51d8-4612-8292-5dbd93be2a5c | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Max" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Max", "variants": [{"label": "A", "rids": ["133"], "count": 1, "dob": ["2013-02-01"], "farbe": ["Marder"], "origin": [], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u7533"], "count": 1, "dob": [], "farbe": ["Schwarz-
|
||||
|
||||
### Drake | id=8d2f8f12-2767-41af-86d9-07ae67530d61 | NeedsInfo | g=00f7dee7-d590-58d2-81b2-0b305049265a l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Drake" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Drake", "decision": "all_distinct", "variants": [{"label": "A", "rids": ["52"], "dob": "2012-06-06", "farbe": "Polarfuchs", "origin": "eigene Zucht", "is_own": true, "matched_gerbil_id": "00f7dee7-d590-58d2-81b2-0b305049265a", "distinct": tr
|
||||
|
||||
### Kim | id=37ad4ebf-241f-4502-9748-f2fdfefac1f9 | NeedsInfo | g=d6247bd3-dba0-52e2-82b2-a386b4e3583e l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Kim" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Kim", "variants": [{"label": "A", "rids": ["25"], "count": 1, "dob": ["2010-11-03"], "farbe": ["Agouti-Schecke"], "origin": ["Clan of little fellows"], "is_own": true, "matched_gerbil_id": "d6247bd3-dba0-52e2-82b2-a386b4e3583e"}, {"label": "
|
||||
|
||||
### Puschel | id=9f1171ec-7654-4e0d-ab1c-617e64974077 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Puschel" kommt mehrfach vor (2 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Puschel", "variants": [{"label": "A", "rids": ["23"], "count": 1, "dob": ["2011-06-13"], "farbe": ["Rotfuchs"], "origin": ["Privatzüchterin Terry M."], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u145", "u1138", "u16
|
||||
|
||||
### Kelly | id=cb0b7dc0-5b91-44e8-8d4f-81f5fc1588f8 | NeedsInfo | g=daf166c8-1a5c-5f58-baea-262841812f89 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Kelly" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Kelly", "variants": [{"label": "A", "rids": ["144"], "count": 1, "dob": ["2013-04-23"], "farbe": ["Agouti"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": "daf166c8-1a5c-5f58-baea-262841812f89"}, {"label": "B", "rids": ["u
|
||||
|
||||
### Mia | id=90a757b4-5599-4cd9-9903-4995305f3051 | NeedsInfo | g=0166b845-6567-5b35-bc72-19f5d8e11112 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Mia" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Mia", "round": 2, "decisions": {"B==C": "same animal (schwarze Mia, Fam.Wendt/Privat) -> merge B(u3600)+C(u3744)", "A": "Zuechterin fragte ob A im Bestand -> beantwortet: ja, isResident=true (Mia von den Kleinen Chaoten, #107, dob 2013-03-04
|
||||
|
||||
### Ben | id=be6e1446-4eef-46a3-8b86-a2fc9e41a699 | NeedsInfo | g=121afa38-2a52-5f0f-8bbf-633b2bdc2c63 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Ben" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Ben", "round": 2, "decision": "all_different", "variants": [{"label": "A", "rids": ["105"], "dob": "2013-03-04", "farbe": "Colourpoint-Agouti-Hell", "origin": "eigene Zucht", "is_own": true, "parents": {"vater": "Flippi", "mutter": "Kyra"},
|
||||
|
||||
### Zeus | id=22bc064b-95c0-4554-9afa-4bcfae7b9539 | NeedsInfo | g=1b37ff31-c735-5178-9bc8-ff3306a2b181 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Zeus" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Zeus", "variants": [{"label": "A", "rids": ["40"], "count": 1, "dob": ["2012-01-27"], "farbe": ["Agouti"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": "1b37ff31-c735-5178-9bc8-ff3306a2b181"}, {"label": "B", "rids": ["u11
|
||||
|
||||
### Eddy | id=b0cc146f-2b12-4d2a-922d-af8f0b4158b2 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Eddy" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Eddy", "variants": [{"label": "A", "rids": ["34"], "count": 1, "dob": ["2011-06-13"], "farbe": ["Kohlfuchsschimmel, hell"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u522"], "count": 1,
|
||||
|
||||
### Yumi | id=7eccb3d8-2996-4ed7-a724-c3d20fd3dd27 | NeedsInfo | g=0cdd9624-461f-55a3-8432-cc99bb23c06c l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Yumi" kommt mehrfach vor (3 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Yumi", "variants": [{"label": "A", "rids": ["19"], "count": 1, "dob": ["2011-04-30"], "farbe": ["Kohlfuchsschimmel"], "origin": ["Kieger mit Krallen"], "is_own": true, "matched_gerbil_id": "0cdd9624-461f-55a3-8432-cc99bb23c06c"}, {"label": "
|
||||
|
||||
### Zora | id=5556d649-5da0-44f2-8838-0c2342f8bf76 | NeedsInfo | g=895917c4-92df-5548-8c1e-d52c4c315d4f l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Zora" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Zora", "variants": [{"label": "A", "rids": ["212"], "count": 1, "dob": ["2015-11-06"], "farbe": ["Blaufuchs-Schecke"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u1053", "u1599", "u1937",
|
||||
|
||||
### Sheila | id=a8c3beb9-f56e-4a20-8886-a4189346d0f5 | NeedsInfo | g=c8192b78-a6ce-5319-8760-e7eeff26ccf0 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Sheila" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Sheila", "variants": [{"label": "A", "rids": ["145"], "count": 1, "dob": ["2014-01-08"], "farbe": ["Algierfuchs"], "origin": ["Clan of Lennylengo"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u1115", "u1658", "u1999
|
||||
|
||||
### Blue | id=2320cd9e-d138-47bc-b9bc-09015deea3b3 | NeedsInfo | g=88cc2206-d166-561a-929c-e68dbafcec43 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Blue" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Blue", "variants": [{"label": "A", "rids": ["139"], "count": 1, "dob": ["2014-01-14"], "farbe": ["Blaufuchsschimmel-hell-Schecke"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": "88cc2206-d166-561a-929c-e68dbafcec43"}, {"l
|
||||
|
||||
### Yuna | id=4edcac77-7e89-438b-aaae-bbc2f4360f0e | NeedsInfo | g=12d2b344-f46b-599b-89e4-c58bb394ffef l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Yuna" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Yuna", "variants": [{"label": "A", "rids": ["121"], "count": 1, "dob": ["2013-08-23"], "farbe": ["Schimmel"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": "12d2b344-f46b-599b-89e4-c58bb394ffef"}, {"label": "B", "rids": ["
|
||||
|
||||
### Amy | id=46ca5a8f-6acc-4500-b0b0-1fb0f128ad41 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Amy" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Amy", "variants": [{"label": "A", "rids": ["87"], "count": 1, "dob": ["2013-02-16"], "farbe": ["Algierfuchsschimmel"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u2918", "u3371", "u6810"]
|
||||
|
||||
### Raya | id=07d1fccf-3f2d-4c61-9502-07901adad4a1 | NeedsInfo | g=1221d293-5b81-552a-b6fd-3721c1a7f57c l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Raya" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Raya", "variants": [{"label": "A", "rids": ["85"], "count": 1, "dob": ["2013-02-02"], "farbe": ["Schimmel"], "origin": ["Zucht der bunten Fellnasen"], "is_own": true, "matched_gerbil_id": "1221d293-5b81-552a-b6fd-3721c1a7f57c"}, {"label": "B
|
||||
|
||||
### Yuki | id=a20feb49-871f-4430-b8a7-f30ef6398a3b | NeedsInfo | g=eac8bd02-2756-5a79-bbc2-3775a925c7df l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Yuki" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Yuki", "variants": [{"label": "A", "rids": ["82"], "count": 1, "dob": ["2012-12-17"], "farbe": ["Algierfuchsschimmel"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": "eac8bd02-2756-5a79-bbc2-3775a925c7df"}, {"label": "B",
|
||||
|
||||
### Mary | id=56d2fd7b-dd74-4416-866a-20b3a7dabb0a | NeedsInfo | g=6ec4527c-c7d6-5e7f-b93a-f3d8c639db34 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Mary" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Mary", "variants": [{"label": "A", "rids": ["31"], "count": 1, "dob": ["2011-09-13"], "farbe": ["Agouti-Schecke"], "origin": ["Seligenstädter Privatzucht"], "is_own": true, "matched_gerbil_id": "6ec4527c-c7d6-5e7f-b93a-f3d8c639db34"}, {"labe
|
||||
|
||||
### Jamie | id=4008796a-3f91-4e02-a434-ff421191044d | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Jamie" kommt mehrfach vor (4 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Jamie", "variants": [{"label": "A", "rids": ["28"], "count": 1, "dob": ["2010-12-27"], "farbe": ["Zobel"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u361", "u2106", "u3629"], "count": 3,
|
||||
|
||||
### Snow | id=0fccefb0-7891-41a0-9e41-d95d5fcd5b50 | NeedsInfo | g=c8543ae3-3a5e-5e96-86ed-d47566d029f7 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Snow" kommt mehrfach vor (5 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Snow", "variants": [{"label": "A", "rids": ["357"], "count": 1, "dob": ["2018-10-26"], "farbe": ["Silberagouti-Schecke"], "origin": ["Kleinen Chaoten"], "is_own": true, "matched_gerbil_id": "c8543ae3-3a5e-5e96-86ed-d47566d029f7"}, {"label":
|
||||
|
||||
### Gina | id=c517d5ed-fdf6-4e01-9517-b05cf2cba556 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Gina" kommt mehrfach vor (5 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Gina", "variants": [{"label": "A", "rids": ["33"], "count": 1, "dob": ["2011-09-09"], "farbe": ["Marder-Schecke"], "origin": ["Zucht der bunten Fellnasen"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u400", "u2861",
|
||||
|
||||
### Blacky | id=3272ddc4-5a78-4564-a170-917c0cdd6885 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Blacky" kommt mehrfach vor (5 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Blacky", "variants": [{"label": "A", "rids": ["1"], "count": 1, "dob": ["2009-07-23"], "farbe": ["Schwarz"], "origin": ["Seligenstädter Privatzucht"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u3686"], "count": 1,
|
||||
|
||||
### Sunny | id=541ff367-aca0-4714-ac5a-e40b02621512 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Sunny" kommt mehrfach vor (6 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Sunny", "variants": [{"label": "A", "rids": ["183"], "count": 1, "dob": [], "farbe": ["Gold"], "origin": ["Privat"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u36", "u1246", "u3457", "u6853"], "count": 4, "dob": []
|
||||
|
||||
### Sam | id=404f3074-520f-4a1c-b1cc-52da82b200e4 | NeedsInfo | g=None l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Sam" kommt mehrfach vor (7 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Sam", "variants": [{"label": "A", "rids": ["219"], "count": 1, "dob": ["2011-10-13"], "farbe": ["Schwarz-Schecke"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": null}, {"label": "B", "rids": ["u1166", "u1726", "u2050"], "
|
||||
|
||||
### Silver | id=ee23d649-0ef9-4a65-ada3-6dfeb5021c63 | NeedsInfo | g=52ab2bd9-34e7-53c7-9515-289ef18a7dc9 l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Silver" kommt mehrfach vor (8 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Silver", "variants": [{"label": "A", "rids": ["99"], "count": 1, "dob": ["2013-03-20"], "farbe": ["Silberagouti"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": "52ab2bd9-34e7-53c7-9515-289ef18a7dc9"}, {"label": "B", "rids
|
||||
|
||||
### Bella | id=237d51cc-7d7a-4785-a317-be1080b0f423 | NeedsInfo | g=3c5b747b-d2e4-5112-b3fc-ba53a87115dc l=None c=None
|
||||
MSG:RennmausPro-Import: Name „Bella" kommt mehrfach vor (8 Varianten) — dasselbe Tier oder verschiedene?
|
||||
A:
|
||||
CTX:{"source": "rpro3-ambiguity", "name": "Bella", "variants": [{"label": "A", "rids": ["98"], "count": 1, "dob": ["2013-03-20"], "farbe": ["Algierfuchs, hell"], "origin": ["eigene Zucht"], "is_own": true, "matched_gerbil_id": "3c5b747b-d2e4-5112-b3fc-ba53a87115dc"}, {"label": "B", "
|
||||
|
||||
### - | id=955e39e6-299c-4f46-b6b7-0556aa9c2673 | NeedsInfo | g=7a960d4a-c088-5976-a5ea-cbee7c9f7d4f l=None c=None
|
||||
MSG:Wieso wird das Tier als Zuchttier angezeigt? Du solltest die Jungtiere aus einer Verpaarung nicht automatisch als Bestandstiere (Zucht- oder Liebhabertier) aufnehmen. Ausnahme es gibt einen Stammbaum,
|
||||
A:
|
||||
CTX:TRIAGE 2026-06-23 Lauf2: isResident-Override-Mechanismus implementiert (merge_and_resolve post-dedup, matcht externalRef oder name+dob). Allgemeine Jungtier-Regel würde 102 resident Breeding-Tiere aus Wurfchronik/docx ohne Stammbaum betreffen (94 benannt, 8 namenlos) -> zu breit
|
||||
|
||||
### Arya Stark von den Kleinen Chaoten | id=e9790985-306d-4f32-94f1-a02a9469e3ad | NeedsInfo | g=b4f59085-5d0d-51b0-9c94-bddf622b5935 l=None c=None
|
||||
MSG:Arya Stark wurde an die Zucht Clan of Black Forest abgegeben und sollte nicht mehr bei meiner Zucht angezeigt werden
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Beatrice von den kleinen Chaoten | id=aa530d1b-1811-469d-990a-d834a9cb65b7 | NeedsInfo | g=cefb6e97-95ca-51ba-976a-02492c6a46de l=None c=None
|
||||
MSG:Eltern fehlen
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Silver von den kleinen Chaoten | id=671f8b5d-e5ce-4b47-aafa-db96fa180e37 | NeedsInfo | g=52ab2bd9-34e7-53c7-9515-289ef18a7dc9 l=None c=None
|
||||
MSG:Vater ist bekannt! Auch von der Mutter fehlt der Stammbaum
|
||||
A:
|
||||
CTX:
|
||||
|
||||
### Odelia von den Kleinen Chaoten | id=d99563fa-a5cf-43da-aaa6-78bd4b677cb2 | NeedsInfo | g=3609e642-73e4-579e-87f1-da0332b1d037 l=None c=None
|
||||
MSG:Falsches Foto
|
||||
A:
|
||||
CTX:Ticket: 'Falsches Foto' bei Odelia (gerbilId 3609e642-...). Befund: GET /gerbils/{id}/photos liefert 3 Fotos (sortOrder 0/1/2), alle 3 Dateien laden serverseitig sauber (HTTP 200, echte JPEG-Bytes: 16585/8305/16104 B). profilePhotoUrl = /photos/files/33ae45c2...jpeg (= sortOrder
|
||||
|
||||
### Zadar from Zeko i ptica, Croatia | id=684f5b7d-8d20-4159-80b2-16b3387b78da | NeedsInfo | g=4b6e40cc-dce9-5212-93aa-b7c5c90fa676 l=None c=None
|
||||
MSG:Eltern sind unbekannt!
|
||||
A:
|
||||
CTX:
|
||||
68
tools/import/research_tickets.py
Normal file
68
tools/import/research_tickets.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Recherche-Helfer: kreuzt jedes NeedsInfo/Open-Ticket gegen ALLE Quellen
|
||||
(_rpro3.db per Name+DOB, .mxp-Backup) und zeigt, was verfügbar ist —
|
||||
damit Rückfragen nur bleiben, wo wirklich nichts gefunden wird."""
|
||||
import json, urllib.request, re, sys
|
||||
import compare_rpro3 as C
|
||||
import rpro3_mxp
|
||||
|
||||
DB = "_rpro3.db"
|
||||
BACKUP = r"C:\Users\gulum\dev\RennmausPro IIIb 06.06.26.backup"
|
||||
|
||||
def norm(s):
|
||||
s = (s or "").lower()
|
||||
for suf in [" von den kleinen chaoten", " v.d. kleinen chaoten", " von den", " of ", " gen. ", " gen "]:
|
||||
pass
|
||||
s = re.split(r"\bvon\b|\bof\b|\bv\.d\.\b|\bgen\.?\b", s)[0]
|
||||
return re.sub(r"[\s._-]", "", s)
|
||||
|
||||
def main():
|
||||
R = C.load_rpro3(DB)
|
||||
animals = R["animals"]
|
||||
by_norm = {}
|
||||
for a in animals:
|
||||
by_norm.setdefault(norm(a["name"]), []).append(a)
|
||||
mxp = rpro3_mxp.load_all(BACKUP)
|
||||
mxp_norm = {norm(k): (k, v) for k, v in mxp.items()}
|
||||
|
||||
urllib.request.urlretrieve("http://localhost:5179/feedback", "fb.json")
|
||||
tickets = [t for t in json.load(open("fb.json", encoding="utf-8"))
|
||||
if not t.get("deletedAt") and t["status"] in ("NeedsInfo", "Open", "Answered")
|
||||
and t.get("gerbilId")]
|
||||
def gv(gid):
|
||||
try:
|
||||
return json.load(urllib.request.urlopen(f"http://localhost:5179/gerbils/{gid}", timeout=15))
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
want = sys.argv[1:]
|
||||
for t in tickets:
|
||||
nm = t.get("entityName") or ""
|
||||
if want and not any(w.lower() in nm.lower() for w in want):
|
||||
continue
|
||||
g = gv(t["gerbilId"])
|
||||
dob = g.get("dateOfBirth")
|
||||
nn = norm(nm)
|
||||
cands = by_norm.get(nn, [])
|
||||
pick = None
|
||||
if dob:
|
||||
pick = next((a for a in cands if a["dob"] == dob), None)
|
||||
if not pick and len(cands) == 1:
|
||||
pick = cands[0]
|
||||
print(f"\n### [{t['status']}] {nm} (live dob={dob}) ticket={t['id'][:8]}")
|
||||
print(f" MSG: {(t.get('message') or '').strip()[:90]}")
|
||||
if pick:
|
||||
print(f" rpro3: farbe={pick['farbe']} | fcode={pick['fcode']} | Vater={pick.get('father')} | Mutter={pick.get('mother')}")
|
||||
elif cands:
|
||||
print(f" rpro3: {len(cands)} Namensvettern, keiner mit DOB {dob}: " +
|
||||
"; ".join(f"{a['dob']}/{a['farbe']}" for a in cands[:5]))
|
||||
else:
|
||||
print(" rpro3: kein Treffer")
|
||||
if nn in mxp_norm:
|
||||
k, v = mxp_norm[nn]
|
||||
pr = v.get("parents", {})
|
||||
print(f" .mxp[{k}]: V={pr.get('Vater',{}).get('name')} M={pr.get('Mutter',{}).get('name')} | Würfe={len(v.get('litters',[]))}")
|
||||
import os; os.remove("fb.json")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
26
tools/import/resolve_blue_ticket.py
Normal file
26
tools/import/resolve_blue_ticket.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ticket_id = "6c5c2678-8b19-4bd3-8ea8-f20eed0c66ad"
|
||||
url = f"http://localhost:5179/feedback/{ticket_id}"
|
||||
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": "Es gab in deiner Zuchtgeschichte tatsächlich zwei unterschiedliche Tiere namens 'Blue':\n1. Den älteren Blue (*14.01.2014, †29.05.2015 aus dem G3-Wurf), der den O5-Wurf gezeugt hat.\n2. Den jüngeren Blue (*12.05.2015, †01.02.2019 aus dem D6-Wurf), der die späteren Würfe (Sheila+Blue und E9) gezeugt hat.\n\nAlle doppelten Platzhalter-Einträge aus der Wurfchronik wurden nun wunschgemäß in diese beiden korrekten Tiere zusammengeführt, sodass die doppelten Einträge verschwunden sind. Bitte lade die Seite neu."
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Status: {res.status}")
|
||||
print("Successfully resolved ticket!")
|
||||
except Exception as e:
|
||||
print("Error:", e)
|
||||
26
tools/import/resolve_gender_filter_ticket.py
Normal file
26
tools/import/resolve_gender_filter_ticket.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ticket_id = "0ecc5449-2c0c-4795-a85d-acb331a622cd"
|
||||
url = f"http://localhost:5179/feedback/{ticket_id}"
|
||||
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": "Die Option 'Unbekannt' wurde aus dem Geschlechts-Filter entfernt, da dieser Wert bei der Suche nach aktiven Tieren/Liebhabern nicht benötigt wird. Bitte lade die Seite neu."
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Status: {res.status}")
|
||||
print("Successfully resolved ticket!")
|
||||
except Exception as e:
|
||||
print("Error:", e)
|
||||
26
tools/import/resolve_missing_alvin_ticket.py
Normal file
26
tools/import/resolve_missing_alvin_ticket.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ticket_id = "4bfabf60-8c5d-4217-a86d-d2f34c159193"
|
||||
url = f"http://localhost:5179/feedback/{ticket_id}"
|
||||
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": "Alvin (Alvin von den kleinen Chaoten) wurde wieder korrekt seinem Wurf (A-Wurf vom 18.02.2010, Eltern Kruke + Blacky) zugeordnet, sodass er dort nun wieder zusammen mit seinem Bruder JackJack aufgelistet wird. Bitte lade die Seite neu."
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Status: {res.status}")
|
||||
print("Successfully resolved ticket!")
|
||||
except Exception as e:
|
||||
print("Error:", e)
|
||||
26
tools/import/resolve_sort_ticket.py
Normal file
26
tools/import/resolve_sort_ticket.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ticket_id = "e31a9d3b-f6aa-44e8-85cb-0aef14e43eb1"
|
||||
url = f"http://localhost:5179/feedback/{ticket_id}"
|
||||
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": "Die Wurf-Liste kann nun über das entsprechende Dropdown-Menü alphabetisch sortiert ('Alphabetisch A-Z' / 'Z-A') sowie nach Jahren gefiltert werden. Bitte lade die Seite neu."
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Status: {res.status}")
|
||||
print("Successfully resolved ticket!")
|
||||
except Exception as e:
|
||||
print("Error:", e)
|
||||
25
tools/import/resolve_ticket_bali.py
Normal file
25
tools/import/resolve_ticket_bali.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ticket_id = "33912984-d51e-46f1-8c6e-a1c561039d2b"
|
||||
url = f"http://localhost:5179/feedback/{ticket_id}"
|
||||
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": "Da Bali ein Tier aus einer Fremdzucht ('Luzerner Krieger's') ist, wurde er durch Anpassung der Cattery-Erkennung aus deinem Wurf (D-Wurf 2010) entfernt und steht nun als Ahn im eigenen Fremdwurf. Bitte lade die Seite neu."
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {ticket_id} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
25
tools/import/resolve_ticket_lotta.py
Normal file
25
tools/import/resolve_ticket_lotta.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
ticket_id = "fa7291cb-a3cc-429e-81b1-1112cf65be2c"
|
||||
url = f"http://localhost:5179/feedback/{ticket_id}"
|
||||
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": "Die Herkunft von Lotta of Nangijala wurde basierend auf ihrem Zucht-Suffix im Namen auf die Cattery 'Nangijala' korrigiert (statt 'Zucht der kleinen Chaoten'). Bitte lade die Seite neu."
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {ticket_id} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
34
tools/import/resolve_tickets_23.py
Normal file
34
tools/import/resolve_tickets_23.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
tickets = [
|
||||
{
|
||||
"id": "7fd5e7a1-aaac-4ef4-80b8-ef391718e9ca",
|
||||
"fixNote": "Die unvollständigen Bezeichnungen aus dem Word-Dokument (wie '23-Wurf') wurden automatisch anhand des Wurfdatums in die korrekte Reihenfolge (z.B. 'H23-Wurf') übersetzt, um Verwechslungen auszuschließen. Bitte lade die Seite neu."
|
||||
},
|
||||
{
|
||||
"id": "5f942e27-d651-4fa7-908b-1938ebb046ee",
|
||||
"fixNote": "Der Eintrag 'A-23 (Fortsetzung Abgabeliste – Seite 7)' wurde als fälschlich importierter Phantom-Wurf identifiziert (es handelte sich um den Abgabevertrag Nr. 23, nicht um einen Wurf) und komplett aus der Datenbank entfernt. Bitte lade die Seite neu."
|
||||
}
|
||||
]
|
||||
|
||||
for t in tickets:
|
||||
url = f"http://localhost:5179/feedback/{t['id']}"
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": t["fixNote"]
|
||||
}
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {t['id']} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error on {t['id']}: {e}")
|
||||
42
tools/import/resolve_tickets_ancestors.py
Normal file
42
tools/import/resolve_tickets_ancestors.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
tickets = [
|
||||
{
|
||||
"id": "721ab06c-7553-4de1-9eb6-585d98bbcfc9",
|
||||
"fixNote": "Der Wurf 'Whiskey × Walpurgis' wurde als fehlerhafter Import eines Zuchtvorfahren-Wurfs identifiziert und Whiskey wurde als Phantom-Datensatz komplett aus der Datenbank entfernt. Bitte lade die Seite neu."
|
||||
},
|
||||
{
|
||||
"id": "63e88dcb-c16f-4708-b821-9dde81c4c7fa",
|
||||
"fixNote": "Stadtmaus Kanani wurde als Zuchtvorfahr klassifiziert und ihr Bestands-Status ('Zuchtanwärter') wurde deaktiviert, da sie nie zum eigenen Bestand gehörte. Bitte lade die Seite neu."
|
||||
},
|
||||
{
|
||||
"id": "7b2e4c00-a94d-4bed-add6-abda190b7c6a",
|
||||
"fixNote": "Sheila of Ulmer Strolche wurde als Zuchtvorfahr klassifiziert und ihr Bestands-Status ('Zuchtanwärter') wurde deaktiviert, da sie nie zum eigenen Bestand gehörte. Bitte lade die Seite neu."
|
||||
},
|
||||
{
|
||||
"id": "29fce1a1-474d-4565-8195-36bb4dccb8c7",
|
||||
"fixNote": "Scarlett of Samsimar wurde als Zuchtvorfahr klassifiziert und ihr Bestands-Status ('Zuchtanwärter') wurde deaktiviert, da sie nie zum eigenen Bestand gehörte. Bitte lade die Seite neu."
|
||||
}
|
||||
]
|
||||
|
||||
for t in tickets:
|
||||
url = f"http://localhost:5179/feedback/{t['id']}"
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": t["fixNote"]
|
||||
}
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {t['id']} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error on {t['id']}: {e}")
|
||||
34
tools/import/resolve_tickets_jackjack.py
Normal file
34
tools/import/resolve_tickets_jackjack.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
tickets = [
|
||||
{
|
||||
"id": "eb2131d9-954d-41f3-982e-a10f1d7e87f4",
|
||||
"fixNote": "Alvin und JackJack wurden erfolgreich im selben Wurf (A-Wurf vom 18.02.2010) zusammengeführt. Die getrennten Wurf-Hälften wurden konsolidiert. Bitte lade die Seite neu."
|
||||
},
|
||||
{
|
||||
"id": "df918dd2-fecb-4a50-a971-41d7c18fbd7c",
|
||||
"fixNote": "Der Wurf wurde mit den RennerPro-Daten abgeglichen. Alvin, JackJack und JackSack sind nun korrekt zusammen im A-Wurf vom 18.02.2010 eingetragen. Bitte lade die Seite neu."
|
||||
}
|
||||
]
|
||||
|
||||
for t in tickets:
|
||||
url = f"http://localhost:5179/feedback/{t['id']}"
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": t["fixNote"]
|
||||
}
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {t['id']} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error on {t['id']}: {e}")
|
||||
34
tools/import/resolve_tickets_not_my_litter.py
Normal file
34
tools/import/resolve_tickets_not_my_litter.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
tickets = [
|
||||
{
|
||||
"id": "0af8e222-a4ac-4f73-9107-e60f34f2dc6b",
|
||||
"fixNote": "Der Wurf 'Bentley × Alexandria' wurde als fehlerhafter Import eines Zuchtvorfahren-Wurfs identifiziert und aus der Datenbank gelöscht. Bitte lade die Seite neu."
|
||||
},
|
||||
{
|
||||
"id": "19bd35f4-9b5d-4eea-a15c-270776a4df1d",
|
||||
"fixNote": "Der Wurf 'Whiskey × Walpurgis' wurde als fehlerhafter Import eines Zuchtvorfahren-Wurfs identifiziert und aus der Datenbank gelöscht. Bitte lade die Seite neu."
|
||||
}
|
||||
]
|
||||
|
||||
for t in tickets:
|
||||
url = f"http://localhost:5179/feedback/{t['id']}"
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": t["fixNote"]
|
||||
}
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {t['id']} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error on {t['id']}: {e}")
|
||||
34
tools/import/resolve_tickets_taro.py
Normal file
34
tools/import/resolve_tickets_taro.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
|
||||
tickets = [
|
||||
{
|
||||
"id": "d13913d0-76f6-4ae4-a055-51708060da70",
|
||||
"fixNote": "Taro wurde fälschlicherweise dem F-Wurf 2010 zugeordnet, weil in der Excel-Datei 'Stammbaum von Kalea.xlsx' fälschlicherweise Floris Geburtsdatum (21.09.2010) für Taro eingetragen war. Wir haben sein Geburtsdatum auf das korrekte Datum (01.09.2012 aus dem U1-Wurf) korrigiert, wodurch er nun im richtigen Wurf mit den Eltern Teiko + Tai steht. Bitte lade die Seite neu."
|
||||
},
|
||||
{
|
||||
"id": "7890f27f-848d-4c69-bf79-4f26b73242f5",
|
||||
"fixNote": "Aufgrund eines Kopierfehlers in der Excel-Stammbaumdatei teilte Taro fälschlicherweise Floris Geburtsdatum (21.09.2010) und stand daher direkt neben ihm im selben Wurf. Nach der Korrektur von Taros Geburtsdatum auf das echte Datum (01.09.2012) ist diese Fehlzuordnung behoben. Bitte lade die Seite neu."
|
||||
}
|
||||
]
|
||||
|
||||
for t in tickets:
|
||||
url = f"http://localhost:5179/feedback/{t['id']}"
|
||||
payload = {
|
||||
"status": "Resolved",
|
||||
"fixNote": t["fixNote"]
|
||||
}
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode('utf-8'),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="PUT"
|
||||
)
|
||||
with urllib.request.urlopen(req) as res:
|
||||
print(f"Ticket {t['id']} -> Status: {res.status}")
|
||||
except Exception as e:
|
||||
print(f"Error on {t['id']}: {e}")
|
||||
@@ -22,7 +22,18 @@ import sys, json
|
||||
from collections import defaultdict
|
||||
import compare_rpro3 as C
|
||||
|
||||
LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
class LettersClass:
|
||||
def __getitem__(self, i):
|
||||
res = ""
|
||||
val = i
|
||||
while val >= 0:
|
||||
res = chr(65 + (val % 26)) + res
|
||||
val = (val // 26) - 1
|
||||
return res
|
||||
def __contains__(self, item):
|
||||
return isinstance(item, str) and item.isalpha() and item.isupper()
|
||||
|
||||
LETTERS = LettersClass()
|
||||
|
||||
|
||||
def informative(recs):
|
||||
|
||||
139
tools/import/rpro3_mxp.py
Normal file
139
tools/import/rpro3_mxp.py
Normal file
@@ -0,0 +1,139 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Parser für RennmausPro-III `.mxp`-Exporte (aus dem Backup
|
||||
`C:\\Users\\gulum\\dev\\RennmausPro IIIb 06.06.26.backup`).
|
||||
|
||||
Eine `.mxp` ist ein latin-1-XML-artiges Format mit drei Abschnitten:
|
||||
<stamm> das Tier selbst (name, clan=Herkunft, sex, geb=Julian Day Number,
|
||||
color="Farbschlag$$Gencode$$...", herk, gew)
|
||||
<baum> Ahnentafel: <bp>-Zeilen, Felder per <#> getrennt:
|
||||
[_, pos(v/m/vv/vm/...), name, clan/adresse, geb, _, _, color, ...]
|
||||
<litter> eigene Würfe: <w>-Blöcke mit <date>, <coparent>, <child>-Zeilen
|
||||
|
||||
Nutzung:
|
||||
python -X utf8 rpro3_mxp.py <backup.zip-oder-mxp-ordner> [Name ...]
|
||||
# ohne Namen: alle Tiere als kompakte Übersicht
|
||||
"""
|
||||
import sys, os, zipfile, json, datetime
|
||||
|
||||
BACKUP = r"C:\Users\gulum\dev\RennmausPro IIIb 06.06.26.backup"
|
||||
|
||||
|
||||
def jdn_to_iso(jdn):
|
||||
try:
|
||||
n = int(str(jdn).strip())
|
||||
except Exception:
|
||||
return None
|
||||
if n <= 0:
|
||||
return None
|
||||
try:
|
||||
return datetime.date.fromordinal(n - 1721425).isoformat()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _split_color(raw):
|
||||
# "Silberagouti-Schecke$$Aa C- D- E- gg Pp Spsp$$$$$$$$schwarz"
|
||||
parts = (raw or "").split("$$")
|
||||
farbschlag = parts[0].strip() if parts else ""
|
||||
gencode = parts[1].strip() if len(parts) > 1 else ""
|
||||
return farbschlag or None, gencode or None
|
||||
|
||||
|
||||
def _tagval(block, tag):
|
||||
key = "<" + tag + ">"
|
||||
for line in block.splitlines():
|
||||
s = line.strip()
|
||||
if s.startswith(key):
|
||||
return s[len(key):].strip()
|
||||
return None
|
||||
|
||||
|
||||
def parse_mxp(text):
|
||||
# Split into sections by top-level tags.
|
||||
stamm = {}
|
||||
if "<stamm>" in text:
|
||||
seg = text.split("<stamm>", 1)[1].split("</stamm>")[0] if "</stamm>" in text else text.split("<stamm>", 1)[1]
|
||||
seg = seg.split("<baum>")[0].split("<litter>")[0]
|
||||
name = _tagval(seg, "name")
|
||||
clan = _tagval(seg, "clan")
|
||||
sex = _tagval(seg, "sex")
|
||||
geb = _tagval(seg, "geb")
|
||||
color = _tagval(seg, "color")
|
||||
fs, gc = _split_color(color)
|
||||
stamm = {"name": name, "clan": clan, "sex": sex,
|
||||
"dob": jdn_to_iso(geb), "farbschlag": fs, "gencode": gc,
|
||||
"zbnr": _tagval(seg, "zbnr"), "gew": _tagval(seg, "gew")}
|
||||
# Ahnentafel: direct parents (pos == 'v' / 'm')
|
||||
parents = {}
|
||||
for line in text.splitlines():
|
||||
s = line.strip()
|
||||
if not s.startswith("<bp>"):
|
||||
continue
|
||||
f = s.split("<#>")
|
||||
if len(f) < 3:
|
||||
continue
|
||||
pos = f[1].strip()
|
||||
if pos not in ("v", "m"):
|
||||
continue
|
||||
nm = f[2].strip()
|
||||
clan = f[3].strip() if len(f) > 3 else ""
|
||||
geb = f[4].strip() if len(f) > 4 else ""
|
||||
color = next((x for x in f if "$$" in x), "")
|
||||
fs, gc = _split_color(color)
|
||||
parents["Vater" if pos == "v" else "Mutter"] = {
|
||||
"name": nm, "clan": clan.split("##")[0] if clan else clan,
|
||||
"dob": jdn_to_iso(geb), "farbschlag": fs, "gencode": gc}
|
||||
# Würfe
|
||||
litters = []
|
||||
if "<litter>" in text:
|
||||
lit = text.split("<litter>", 1)[1]
|
||||
for wblock in lit.split("<w>")[1:]:
|
||||
date = jdn_to_iso(_tagval(wblock, "date"))
|
||||
co = _tagval(wblock, "coparent") or ""
|
||||
coname = co.split("$$")[0].strip() if co else ""
|
||||
children = []
|
||||
for line in wblock.splitlines():
|
||||
s = line.strip()
|
||||
if s.startswith("<child>"):
|
||||
cf = s.split("<#>")
|
||||
csex = cf[2].strip() if len(cf) > 2 else ""
|
||||
ccolor = next((x for x in cf if "$$" in x), "")
|
||||
cfs, _ = _split_color(ccolor)
|
||||
# child name is usually empty in export; keep sex+color
|
||||
children.append({"sex": csex, "farbschlag": cfs})
|
||||
litters.append({"date": date, "coparent": coname, "children": len(children),
|
||||
"child_details": children})
|
||||
return {"stamm": stamm, "parents": parents, "litters": litters}
|
||||
|
||||
|
||||
def load_all(src=BACKUP):
|
||||
out = {}
|
||||
if os.path.isfile(src) and zipfile.is_zipfile(src):
|
||||
z = zipfile.ZipFile(src)
|
||||
for n in z.namelist():
|
||||
if n.lower().endswith(".mxp"):
|
||||
txt = z.read(n).decode("latin-1", "replace")
|
||||
out[os.path.splitext(os.path.basename(n))[0]] = parse_mxp(txt)
|
||||
else:
|
||||
for n in os.listdir(src):
|
||||
if n.lower().endswith(".mxp"):
|
||||
txt = open(os.path.join(src, n), encoding="latin-1").read()
|
||||
out[os.path.splitext(n)[0]] = parse_mxp(txt)
|
||||
return out
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
src = sys.argv[1] if len(sys.argv) > 1 else BACKUP
|
||||
want = [a.lower() for a in sys.argv[2:]]
|
||||
data = load_all(src)
|
||||
for key in sorted(data):
|
||||
if want and key.lower() not in want:
|
||||
continue
|
||||
d = data[key]
|
||||
st = d["stamm"]
|
||||
print(f"\n### {key} ({st.get('name')}, {st.get('sex')}, *{st.get('dob')})")
|
||||
print(f" Herkunft: {st.get('clan')} | Farbe: {st.get('farbschlag')} [{st.get('gencode')}]")
|
||||
for role, p in d["parents"].items():
|
||||
print(f" {role}: {p['name']} ({p.get('clan')}, *{p.get('dob')}) {p.get('farbschlag')} [{p.get('gencode')}]")
|
||||
for l in d["litters"]:
|
||||
print(f" Wurf {l['date']} x {l['coparent']} -> {l['children']} Junge")
|
||||
82
tools/import/rpro3_pedigree.py
Normal file
82
tools/import/rpro3_pedigree.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Rekursive Ahnentafel aus _rpro3.db: verfolgt Eltern-Zeiger (pid_raw/mid_raw)
|
||||
ueber ALLE Generationen zurueck. Gibt Vorfahren + Eltern-Kind-Links aus.
|
||||
|
||||
python -X utf8 rpro3_pedigree.py "<Name>" [dob]
|
||||
"""
|
||||
import sys
|
||||
import compare_rpro3 as C
|
||||
|
||||
DB = "_rpro3.db"
|
||||
|
||||
|
||||
def build():
|
||||
R = C.load_rpro3(DB)
|
||||
A = R["animals"]
|
||||
by_rid = {a["rid"]: a for a in A}
|
||||
return A, by_rid
|
||||
|
||||
|
||||
def norm(s):
|
||||
import re
|
||||
s = (s or "").lower()
|
||||
s = re.split(r"\bvon\b|\bof\b|\bv\.d\.\b|\bgen\.?\b", s)[0]
|
||||
return re.sub(r"[\s._-]", "", s)
|
||||
|
||||
|
||||
def find(A, name, dob=None):
|
||||
cs = [a for a in A if norm(a["name"]) == norm(name)]
|
||||
if dob:
|
||||
m = next((a for a in cs if a["dob"] == dob), None)
|
||||
if m:
|
||||
return m
|
||||
return cs[0] if len(cs) == 1 else None
|
||||
|
||||
|
||||
def walk(root, by_rid):
|
||||
"""Return (nodes {rid:animal}, links [(child_rid, father_rid, mother_rid)]) via ancestors."""
|
||||
nodes, links, seen = {}, [], set()
|
||||
stack = [root]
|
||||
while stack:
|
||||
a = stack.pop()
|
||||
if not a or a["rid"] in seen:
|
||||
continue
|
||||
seen.add(a["rid"])
|
||||
nodes[a["rid"]] = a
|
||||
f = by_rid.get(a.get("pid_raw"))
|
||||
m = by_rid.get(a.get("mid_raw"))
|
||||
if f or m:
|
||||
links.append((a["rid"], f["rid"] if f else None, m["rid"] if m else None))
|
||||
for p in (f, m):
|
||||
if p and p["rid"] not in seen:
|
||||
stack.append(p)
|
||||
return nodes, links
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
name = sys.argv[1]
|
||||
dob = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
A, by_rid = build()
|
||||
root = find(A, name, dob)
|
||||
if not root:
|
||||
print("nicht gefunden"); sys.exit(1)
|
||||
nodes, links = walk(root, by_rid)
|
||||
print(f"Wurzel: {root['name']} (*{root['dob']}) | Vorfahren gesamt: {len(nodes)-1} | Links: {len(links)}")
|
||||
# depth per node
|
||||
depth = {root["rid"]: 0}
|
||||
changed = True
|
||||
while changed:
|
||||
changed = False
|
||||
for c, f, m in links:
|
||||
for p in (f, m):
|
||||
if p and c in depth and depth.get(p, -1) < depth[c] + 1:
|
||||
depth[p] = depth[c] + 1
|
||||
changed = True
|
||||
for rid in sorted(nodes, key=lambda r: depth.get(r, 0)):
|
||||
a = nodes[rid]
|
||||
d = depth.get(rid, 0)
|
||||
print(f" gen{d}: {a['name']} (*{a['dob']}, {a['farbe']} [{a['fcode']}], Herkunft {a['origin']})")
|
||||
print("\nLinks (Kind <- Vater x Mutter):")
|
||||
for c, f, m in links:
|
||||
print(f" {nodes[c]['name']} (*{nodes[c]['dob']}) <- "
|
||||
f"{nodes[f]['name'] if f else '?'} x {nodes[m]['name'] if m else '?'}")
|
||||
@@ -274,6 +274,26 @@ check("FIX-4: no artifact -> geno unchanged",
|
||||
check("FIX-4: no artifact -> no spurious death",
|
||||
death5 == "")
|
||||
|
||||
# --- FIX (ab8fdb0b): leading death-marker right after DOB must not leak into geno ---
|
||||
# bare "/+," (Mamono) — death without date
|
||||
_, _, geno_m = e.parse_detail("Mamono,*02.08.2020/+, Aa C- D- Ee gg PP spsp")
|
||||
check("FIX-ab8fdb0b: bare '/+,' stripped from geno (Mamono)",
|
||||
geno_m == "Aa C- D- Ee gg PP spsp")
|
||||
# "/+<Textmonth>'<year>" (Talula) — text-month death marker
|
||||
_, _, geno_t = e.parse_detail("Talula,*01.01.2015/+April'2017, aa C- DD ee GG PP spsp")
|
||||
check("FIX-ab8fdb0b: '/+Textmonth'year' stripped from geno (Talula)",
|
||||
geno_t == "aa C- DD ee GG PP spsp")
|
||||
# leading "+<numeric date>" (Fegur) — death date captured, geno clean
|
||||
dob_f, death_f, geno_f = e.parse_detail("Fegur,*01.01.2016+09.07.2017, aa CC DD ee GG PP spsp")
|
||||
check("FIX-ab8fdb0b: leading '+date' stripped from geno (Fegur)",
|
||||
geno_f == "aa CC DD ee GG PP spsp")
|
||||
check("FIX-ab8fdb0b: leading '+date' still captured as death (Fegur)",
|
||||
death_f == "09.07.2017")
|
||||
# "/+ ," (Flippi) — death marker with trailing comma, no date
|
||||
_, _, geno_fl = e.parse_detail("Flippi,*01.01.2016/+ , aa CC DD ee GG PP spsp")
|
||||
check("FIX-ab8fdb0b: '/+ ,' stripped from geno (Flippi)",
|
||||
geno_fl == "aa CC DD ee GG PP spsp")
|
||||
|
||||
# --- name-bleed guard (a parent name is not a Farbschlag) ---
|
||||
check("v.d. name rejected", e.looks_like_animal_name("Tennessee von den Kleinen Chaoten"))
|
||||
check("gen.+v.d. name rejected", e.looks_like_animal_name("Victoria Welby gen. Welby v.d. Kleinen Chaoten"))
|
||||
|
||||
@@ -487,6 +487,56 @@ _, _g_add = m.resolve_color_and_genotype("Agouti Schecke", "AA CC DD EE GG PP",
|
||||
check("schecke label + no Sp token -> appends Spsp", "Spsp" in _g_add)
|
||||
|
||||
|
||||
# ── parse_death_info: markerless death dates (Ticket ec9267b9) ──────────────────
|
||||
# A death keyword without a +/cross marker before the date must still yield the
|
||||
# death date. Status logic is unchanged; an existing dateOfDeath is never replaced.
|
||||
_st, _dod, _cod = m.parse_death_info(
|
||||
"Verstorbener Welpe am 30.03.15 an Durchfall nach frühem Abstillen wegen Tod der Mutter.",
|
||||
"Breeding", None, None)
|
||||
check("ec9267b9: markerless 'Verstorben ... am DD.MM.YY' -> Deceased", _st == "Deceased")
|
||||
check("ec9267b9: markerless death date parsed (30.03.15 -> 2015-03-30)", _dod == "2015-03-30")
|
||||
# 'Verstorben am DD.MM.YY' (the GivenAway-then-died notes) — date now captured.
|
||||
_st2, _dod2, _ = m.parse_death_info("Verstorben am 04.12.18 an Leberzyste", "GivenAway", None, None)
|
||||
check("ec9267b9: 'Verstorben am 04.12.18' -> Deceased + date", _st2 == "Deceased" and _dod2 == "2018-12-04")
|
||||
# Never overwrite an existing dateOfDeath.
|
||||
_st3, _dod3, _ = m.parse_death_info("Verstorben am 04.12.18", "Breeding", "2017-01-01", None)
|
||||
check("ec9267b9: existing dateOfDeath kept (not overwritten)", _dod3 == "2017-01-01")
|
||||
# No death keyword -> no spurious date / status change.
|
||||
_st4, _dod4, _ = m.parse_death_info("Geboren am 30.03.15", "Breeding", None, None)
|
||||
check("ec9267b9: no death keyword -> Status/date unchanged", _st4 == "Breeding" and _dod4 is None)
|
||||
|
||||
|
||||
# ── enrich_from_contracts: excludeContractMatch gate (parent-not-pup) ───────────
|
||||
# A parent animal pinned out via excludeContractMatch must NEVER receive a
|
||||
# contract's receiver/gohome/GivenAway, even when its call-name matches.
|
||||
_excl_gerbils = [{
|
||||
"Id": "g-makoto", "Name": "Makoto von den Kleinen Chaoten", "Gender": "male",
|
||||
"Status": "Breeding", "DateOfBirth": "2016-05-01", "ReceiverContactId": None,
|
||||
"GoHomeDate": None, "OriginBreeder": "Zucht der kleinen Chaoten",
|
||||
"ExternalRef": "stammbaum-makoto", "Provenance": None,
|
||||
}]
|
||||
_excl_contract = [{
|
||||
"sourceFile": "Zucht der kleinen Chaoten _ Balu (Makoto.Ella)-Thomas Weickert.docx",
|
||||
"buyer": "Thomas Weickert", "animals": ["Makoto"], "color": "",
|
||||
"gender": "", "dob": "", "handoverDate": "2017-06-01", "contractDate": "2017-06-01",
|
||||
"price": "",
|
||||
}]
|
||||
_excl_decisions = [{"name": "Makoto", "dob": "2016-05-01", "excludeContractMatch": True}]
|
||||
_es, _ = m.enrich_from_contracts(_excl_contract, _excl_gerbils, {}, {},
|
||||
exclude_decisions=_excl_decisions)
|
||||
check("excludeContractMatch: pinned parent keeps no receiver",
|
||||
_excl_gerbils[0].get("ReceiverContactId") is None)
|
||||
check("excludeContractMatch: pinned parent stays Breeding (not GivenAway)",
|
||||
_excl_gerbils[0].get("Status") == "Breeding")
|
||||
check("excludeContractMatch: pinned parent gets no GoHomeDate",
|
||||
_excl_gerbils[0].get("GoHomeDate") is None)
|
||||
# Without the exclude, the same match WOULD set the receiver (control).
|
||||
_excl_gerbils2 = [dict(_excl_gerbils[0])]
|
||||
m.enrich_from_contracts(_excl_contract, _excl_gerbils2, {}, {}, exclude_decisions=[])
|
||||
check("excludeContractMatch: control (no exclude) -> receiver IS set",
|
||||
_excl_gerbils2[0].get("ReceiverContactId") is not None)
|
||||
|
||||
|
||||
# ── Integration: assert the resolved_import.json output reflects the ticket fixes ──
|
||||
# (Only when the pipeline has already been run; tolerant if the file is absent.)
|
||||
import os as _os, json as _json
|
||||
@@ -552,13 +602,112 @@ if _os.path.exists(_resolved):
|
||||
_roni = next((g for g in _d["gerbils"]
|
||||
if g["Name"] == "Roni" and g.get("DateOfBirth") == "2022-01-27"), None)
|
||||
check("Roni: gender flipped to male", _roni is not None and _roni.get("Gender") == "male")
|
||||
# Fumi: materialised stub that is the (Wurfchronik) MOTHER of T21/Z21/22 →
|
||||
# under the isResident-Sweep (Ticket 381f7e51) a parent of her OWN litters is
|
||||
# resident. (No isResident override in conflict-decisions, so the sweep decides.)
|
||||
_fumi = _find("Fumi von den Kleinen")
|
||||
check("Fumi: materialised as a non-resident stub",
|
||||
_fumi is not None and _fumi.get("IsResident") is False)
|
||||
check("Fumi: materialised; resident as a parent of her own Wurfchronik litters",
|
||||
_fumi is not None and _fumi.get("IsResident") is True)
|
||||
|
||||
# Sunny von PZ Karl: father corrected Hiro → Bill von Privat.
|
||||
_check_parents("Sunny (parents)", "Sunny von PZ Karl", "Bill von Privat", "Melly von Privat")
|
||||
|
||||
# ── Akane (Ticket 36a3fcde): addLitters injection + isResident/notes/receiver
|
||||
# overrides + ShowInChronicle. The manually-added litter must hang off the
|
||||
# EXISTING Akane and the new Bonaparte stub, link the three children, and be
|
||||
# hidden from the Wurfchronik. ───────────────────────────────────────────
|
||||
_akane = _find("Akane", "2023-01-21")
|
||||
check("Akane: record present (*2023-01-21)", _akane is not None)
|
||||
if _akane:
|
||||
check("Akane: isResident override == False", _akane.get("IsResident") is False)
|
||||
check("Akane: receiver = Ulrike Neu",
|
||||
_akane.get("ReceiverContactId") == "33130df1-e164-54ae-be74-a9b7d2ced11b")
|
||||
check("Akane: Lebenslauf-Notes mention Ulrike Neu",
|
||||
"Ulrike Neu" in (_akane.get("Notes") or ""))
|
||||
|
||||
# The injected litter (deterministic ExternalRef from the slug).
|
||||
_alit = next((l for l in _d["litters"]
|
||||
if l.get("ExternalRef") == "decision-litter-akaneswurfbeiclanofblackforest"), None)
|
||||
check("addLitters: Akane litter injected", _alit is not None)
|
||||
if _alit:
|
||||
check("addLitters: ShowInChronicle == False", _alit.get("ShowInChronicle") is False)
|
||||
check("addLitters: mother is Akane",
|
||||
_akane is not None and _alit.get("MotherId") == _akane["Id"])
|
||||
_bona = _G.get(_alit.get("FatherId"))
|
||||
check("addLitters: father is Bonaparte von den Schlossmäusen",
|
||||
_bona is not None and _bona["Name"].startswith("Bonaparte"))
|
||||
# The three children must point their LitterId at the injected litter.
|
||||
_kids = {g["Name"]: g for g in _d["gerbils"]
|
||||
if g.get("LitterId") == _alit["Id"]}
|
||||
for _kn in ("Merle", "Fanella", "Pete"):
|
||||
check(f"addLitters: child {_kn} linked to the litter", _kn in _kids)
|
||||
check("addLitters: Merle is the new resident stub (not 'Merle of Samsimar')",
|
||||
_kids.get("Merle") is not None and _kids["Merle"].get("IsResident") is True)
|
||||
check("addLitters: Pete resident", _kids.get("Pete") is not None
|
||||
and _kids["Pete"].get("IsResident") is True)
|
||||
check("addLitters: Fanella non-resident, receiver Ulrike Neu",
|
||||
_kids.get("Fanella") is not None
|
||||
and _kids["Fanella"].get("IsResident") is False
|
||||
and _kids["Fanella"].get("ReceiverContactId") == "33130df1-e164-54ae-be74-a9b7d2ced11b")
|
||||
|
||||
# ShowInChronicle (Ticket ea41257a): present on EVERY litter. The Wurfchronik
|
||||
# shows only the breeder's own documented litters. Pure ancestor pairings
|
||||
# (reconstructed from Stammbaum diagrams, NOT from the Wurfchronik, with NO
|
||||
# resident parent) are hidden; the Akane addLitter stays hidden too; every
|
||||
# real Wurfchronik litter and any reconstructed litter with a resident parent
|
||||
# stays visible.
|
||||
check("ShowInChronicle: present on every litter",
|
||||
all("ShowInChronicle" in l for l in _d["litters"]))
|
||||
|
||||
def _prov_of(l):
|
||||
try:
|
||||
return _json.loads(l.get("Provenance") or "{}")
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
def _is_reconstructed(l):
|
||||
p = _prov_of(l)
|
||||
notes = " ".join(p.get("notes") or []).lower()
|
||||
return ("rekonstruiert" in notes) and not p.get("fromWurfchronik")
|
||||
|
||||
def _has_resident_parent(l):
|
||||
for pid in (l.get("FatherId"), l.get("MotherId")):
|
||||
g = _G.get(pid)
|
||||
if g and g.get("IsResident"):
|
||||
return True
|
||||
return False
|
||||
|
||||
_hidden = [l for l in _d["litters"] if l.get("ShowInChronicle") is False]
|
||||
# (a) the manually injected Akane litter is still hidden.
|
||||
check("ShowInChronicle: Akane addLitter still hidden",
|
||||
any(l.get("ExternalRef") == "decision-litter-akaneswurfbeiclanofblackforest"
|
||||
for l in _hidden))
|
||||
# (b) every pure ancestor pairing (reconstructed, no resident parent) is hidden;
|
||||
# and there is at least one such litter (the ticket case 47f8d2b6).
|
||||
_pure_ancestor = [l for l in _d["litters"]
|
||||
if _is_reconstructed(l) and not _has_resident_parent(l)]
|
||||
check("ShowInChronicle: at least one pure ancestor pairing exists",
|
||||
len(_pure_ancestor) > 0)
|
||||
check("ShowInChronicle: every pure ancestor pairing is hidden",
|
||||
all(l.get("ShowInChronicle") is False for l in _pure_ancestor))
|
||||
# (c) the concrete ticket litter 47f8d2b6 (Antares × Charly) is hidden.
|
||||
_ticket_lit = _L.get("47f8d2b6-bf13-5f94-935c-f8860a5a1ce6")
|
||||
check("ShowInChronicle: ticket litter 47f8d2b6 present", _ticket_lit is not None)
|
||||
if _ticket_lit:
|
||||
check("ShowInChronicle: ticket litter 47f8d2b6 hidden",
|
||||
_ticket_lit.get("ShowInChronicle") is False)
|
||||
# (d) regression — a real Wurfchronik litter stays visible; and reconstructed
|
||||
# litters WITH a resident parent (the breeder's own, only charted) stay
|
||||
# visible, so her real litters are never hidden.
|
||||
_wurfchronik_lits = [l for l in _d["litters"] if _prov_of(l).get("fromWurfchronik")]
|
||||
check("ShowInChronicle: Wurfchronik litters present", len(_wurfchronik_lits) > 0)
|
||||
check("ShowInChronicle: every Wurfchronik litter visible",
|
||||
all(l.get("ShowInChronicle") is True for l in _wurfchronik_lits))
|
||||
_recon_resident = [l for l in _d["litters"]
|
||||
if _is_reconstructed(l) and _has_resident_parent(l)]
|
||||
check("ShowInChronicle: reconstructed litter with resident parent stays visible",
|
||||
all(l.get("ShowInChronicle") is True for l in _recon_resident))
|
||||
|
||||
# Danielle: mother = Ella *10.06.2019, father = Makoto (sibling pairing; Ticket 4692fd5c).
|
||||
_dan = _find("Danielle von den Kleinen")
|
||||
_df, _dm = _parents(_dan)
|
||||
@@ -570,18 +719,42 @@ if _os.path.exists(_resolved):
|
||||
check("Danielle: mother Ella is the *2019-06-10 one (not the *2023 Ella)",
|
||||
_dmom is not None and _dmom.get("DateOfBirth") == "2019-06-10")
|
||||
|
||||
# Eddy: ticket 439b02e4 & Eliza: ticket b43a5e67
|
||||
_eddy = _find("Eddy von den Kleinen")
|
||||
_eliza = _find("Eliza", "2010-08-20")
|
||||
check("Eddy: present", _eddy is not None)
|
||||
check("Eliza: present", _eliza is not None)
|
||||
if _eddy and _eliza:
|
||||
_el = _L.get(_eddy.get("LitterId"))
|
||||
check("E-Wurf 2010: present", _el is not None)
|
||||
if _el:
|
||||
check("E-Wurf 2010: father is Blacky", _el.get("FatherId") is not None and _G[_el["FatherId"]]["Name"].startswith("Blacky"))
|
||||
check("E-Wurf 2010: mother is Kruke", _el.get("MotherId") is not None and _G[_el["MotherId"]]["Name"] == "Kruke")
|
||||
check("Eliza: shares same litter with Eddy", _eliza.get("LitterId") == _eddy.get("LitterId"))
|
||||
|
||||
# Zeus + Beatrice vs Eddy + Sheila same-date litters (2012-06-13)
|
||||
_k1 = next((l for l in _d["litters"] if l.get("Name") == "Wurf K1" and l.get("Date") == "2012-06-13"), None)
|
||||
_ed_sh = next((l for l in _d["litters"] if "Eddy" in l.get("Name") and "Sheila" in l.get("Name") and l.get("Date") == "2012-06-13"), None)
|
||||
check("K1-Wurf: present on 2012-06-13", _k1 is not None)
|
||||
check("Eddy+Sheila litter: present on 2012-06-13", _ed_sh is not None)
|
||||
if _k1 and _ed_sh:
|
||||
check("K1-Wurf and Eddy+Sheila litter are distinct", _k1["Id"] != _ed_sh["Id"])
|
||||
check("K1-Wurf has correct father Zeus", _k1.get("FatherId") is not None and _G[_k1["FatherId"]]["Name"].startswith("Zeus"))
|
||||
check("K1-Wurf has correct mother Beatrice", _k1.get("MotherId") is not None and _G[_k1["MotherId"]]["Name"].startswith("Beatrice"))
|
||||
check("Eddy+Sheila litter is hidden from chronicle", _ed_sh.get("ShowInChronicle") is False)
|
||||
|
||||
# Catelyn (Ticket 7bbc045c): father Eddard Stark of Sunset Glow, mother Milena.
|
||||
_check_parents("Catelyn", "Catelyn Stark von den Kleinen", "Eddard Stark", "Milena")
|
||||
|
||||
# Gaida (Ticket ba63325a): Geschwisterverpaarung Zhuāngzǐ × Zaibunissa (beide *2020-02-21).
|
||||
_check_parents("Gaida", "Gaida von den Kleinen Chaoten", "Zhuāngzǐ", "Zaibunissa")
|
||||
|
||||
# Bentley / Alexandria / Bugatti (Ticket 09bcac78 / 45cc501b): nur Vorfahren → isResident False.
|
||||
# Bentley / Alexandria / Bugatti (Ticket 09bcac78 / 45cc501b): suppressed by decision -> None.
|
||||
for _tag, _ref in [("Bentley", "Wurfchronik Teil 1_page_0054.md-50505050-0003-4000-8000-000000000003"),
|
||||
("Alexandria", "Wurfchronik Teil 1_page_0054.md-50505050-0004-4000-8000-000000000004"),
|
||||
("Bugatti", "Wurfchronik Teil 1_page_0054.md-40404040-0003-4000-8000-000000000003")]:
|
||||
_g = next((g for g in _d["gerbils"] if g.get("ExternalRef") == _ref), None)
|
||||
check(f"{_tag}: isResident override == False", _g is not None and _g.get("IsResident") is False)
|
||||
check(f"{_tag}: suppressed by decision", _g is None)
|
||||
|
||||
# Cherry Berry's Quqquluuruu: gender override female (box colour misread).
|
||||
_cherry = _find("Cherry Berry")
|
||||
@@ -655,6 +828,90 @@ if _os.path.exists(_resolved):
|
||||
_mf, _mm = _parents(_mamta)
|
||||
check("Mamta Mini: father Geely, mother Gaida linked at the litter",
|
||||
(_mf or "").startswith("Geely") and (_mm or "").startswith("Gaida"))
|
||||
|
||||
# ── isResident-Sweep (Ticket 381f7e51): „ALLE raus, AUSSER Elterntiere" ───────
|
||||
# Datengetriebene Endregel: resident GENAU DANN, wenn (1) expliziter Override
|
||||
# ODER (2) Elternteil eines EIGENEN Wurfs (Wurfchronik/Clan/resident-Elternteil),
|
||||
# NICHT bloß eines rein-virtuellen Ahnen-Wurfs.
|
||||
_byid = lambda pref: next((g for g in _d["gerbils"]
|
||||
if g.get("Id", "").startswith(pref)), None)
|
||||
|
||||
# (a) Jungtier ohne eigene Nachzucht (namenloses ♀ *2022-01-28, O20) → False.
|
||||
_o20 = _byid("86c10cf2")
|
||||
check("Sweep: jungling 86c10cf2 (no own offspring) → isResident False",
|
||||
_o20 is not None and _o20.get("IsResident") is False)
|
||||
|
||||
# (b) Mindestens 90 % aller Tiere sind jetzt NICHT-resident (der Blanket-True-
|
||||
# Default der Wurfchronik ist weg; vorher waren ~1709/2357 resident).
|
||||
_n_res = sum(1 for g in _d["gerbils"] if g.get("IsResident"))
|
||||
check("Sweep: resident count drastically reduced (< 700)", _n_res < 700)
|
||||
|
||||
# (c) Echte Zuchttiere (Eltern dokumentierter Wurfchronik-Würfe) bleiben True.
|
||||
def _is_wurfchronik(l):
|
||||
try:
|
||||
return bool(_json.loads(l.get("Provenance") or "{}").get("fromWurfchronik"))
|
||||
except Exception:
|
||||
return False
|
||||
_wc_parents_true = 0
|
||||
_wc_parents_total = 0
|
||||
for l in _d["litters"]:
|
||||
if not _is_wurfchronik(l):
|
||||
continue
|
||||
for pid in (l.get("FatherId"), l.get("MotherId")):
|
||||
pg = _G.get(pid)
|
||||
if not pg:
|
||||
continue
|
||||
_wc_parents_total += 1
|
||||
if pg.get("IsResident"):
|
||||
_wc_parents_true += 1
|
||||
# The vast majority of Wurfchronik parents are her own breeding stock → resident
|
||||
# (a handful are explicit-false ancestors like Bentley/Alexandria).
|
||||
check("Sweep: ≥ 95% of Wurfchronik-litter parents stay resident",
|
||||
_wc_parents_total > 0 and _wc_parents_true / _wc_parents_total >= 0.95)
|
||||
|
||||
# (d) Externer Ahne, nur Elternteil eines virtuellen Ahnen-Wurfs → False.
|
||||
_antares = _find("Antares of Ulmer Strolche")
|
||||
check("Sweep: external ancestor Antares (virtual-only litter) → isResident False",
|
||||
_antares is not None and _antares.get("IsResident") is False)
|
||||
|
||||
# (e) Expliziter false-Override gewinnt über Elternschaft (Akane *2023-01-21 ist
|
||||
# Elternteil ihres Fremd-Wurfs, bleibt aber False per Override).
|
||||
_ak = _find("Akane", "2023-01-21")
|
||||
check("Sweep: explicit false override beats parenthood (Akane → False)",
|
||||
_ak is not None and _ak.get("IsResident") is False)
|
||||
|
||||
# (f) Residenten, die KEIN Elternteil irgendeines Wurfs sind, sind ausschließlich
|
||||
# explizite Overrides (z. B. die addAnimals-Stubs Merle/Pete) — der Sweep
|
||||
# macht niemanden ohne Elternschaft resident.
|
||||
_parent_ids = set()
|
||||
for l in _d["litters"]:
|
||||
for pid in (l.get("FatherId"), l.get("MotherId")):
|
||||
if pid:
|
||||
_parent_ids.add(pid)
|
||||
# Ein expliziter isResident:true-Override in conflict-decisions.json macht ein
|
||||
# NICHT-Elterntier legitim resident (Züchterin-Entscheidung, z. B. „extern"-Badge
|
||||
# entfernen). Deren Match-Keys (name / externalRef) werden neben den decision--Stubs
|
||||
# akzeptiert — sonst würde jede solche Kuratierung diese Invariante verletzen.
|
||||
_cd_path = _os.path.join(_os.path.dirname(__file__), "conflict-decisions.json")
|
||||
_ovr_names, _ovr_refs = set(), []
|
||||
if _os.path.exists(_cd_path):
|
||||
for _r in (_json.load(open(_cd_path, encoding="utf-8")).get("resolutions") or []):
|
||||
if _r.get("isResident") is True:
|
||||
if _r.get("name"):
|
||||
_ovr_names.add(m.normalize_name(_r["name"]))
|
||||
if _r.get("externalRef"):
|
||||
_ovr_refs.append(_r["externalRef"])
|
||||
|
||||
def _res_ok(g):
|
||||
er = g.get("ExternalRef") or ""
|
||||
return (er.startswith("decision-")
|
||||
or m.normalize_name(g.get("Name") or "") in _ovr_names
|
||||
or any(er.endswith(ref) for ref in _ovr_refs))
|
||||
|
||||
_res_nonparent = [g for g in _d["gerbils"]
|
||||
if g.get("IsResident") and g["Id"] not in _parent_ids]
|
||||
check("Sweep: residents that are not a parent are only explicit override stubs",
|
||||
all(_res_ok(g) for g in _res_nonparent))
|
||||
else:
|
||||
print("note: output/resolved_import.json not present — skipped integration assertions")
|
||||
|
||||
|
||||
130
tools/triage_active_tickets.py
Normal file
130
tools/triage_active_tickets.py
Normal file
@@ -0,0 +1,130 @@
|
||||
import urllib.request
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
base_url = "http://localhost:5179"
|
||||
output_file = r"C:\Users\gulum\dev\GerbilManager\docs\active-triage-summary.md"
|
||||
|
||||
def fetch_json(path):
|
||||
url = f"{base_url}{path}"
|
||||
try:
|
||||
req = urllib.request.Request(url)
|
||||
with urllib.request.urlopen(req) as r:
|
||||
return json.loads(r.read().decode('utf-8'))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def main():
|
||||
print("Fetching active tickets...")
|
||||
all_tickets = fetch_json("/feedback")
|
||||
if not all_tickets:
|
||||
print("Error: Could not retrieve tickets from API. Is the server running?")
|
||||
sys.exit(1)
|
||||
|
||||
active_tickets = []
|
||||
for t in all_tickets:
|
||||
status = t.get("status")
|
||||
if status in ("Open", "Answered"):
|
||||
active_tickets.append(t)
|
||||
elif status == "NeedsInfo":
|
||||
thread = t.get("thread", [])
|
||||
if thread and thread[-1].get("role") == "breeder":
|
||||
active_tickets.append(t)
|
||||
print(f"Found {len(active_tickets)} active tickets.")
|
||||
|
||||
markdown_content = []
|
||||
markdown_content.append("# Active Tickets Triage Summary")
|
||||
markdown_content.append(f"*Generated automatically on 2026-06-28. Total active: {len(active_tickets)}*\n")
|
||||
markdown_content.append("This file aggregates all active feedback tickets with their full database context and source provenance to allow quick resolution.\n")
|
||||
markdown_content.append("---")
|
||||
|
||||
for idx, t in enumerate(active_tickets, 1):
|
||||
tid = t.get("id")
|
||||
status = t.get("status")
|
||||
msg = t.get("message") or "No message"
|
||||
category = t.get("category") or "General"
|
||||
entity_name = t.get("entityName") or "None"
|
||||
gerbil_id = t.get("gerbilId")
|
||||
litter_id = t.get("litterId")
|
||||
question = t.get("question")
|
||||
answer = t.get("answer")
|
||||
agent_context = t.get("agentContext")
|
||||
|
||||
markdown_content.append(f"\n## {idx}. [{status}] Ticket `{tid[:8]}` (ID: `{tid}`)")
|
||||
markdown_content.append(f"- **Breeder's Message**: \"{msg.strip()}\"")
|
||||
markdown_content.append(f"- **Category**: `{category}` | **Target Name**: `{entity_name}`")
|
||||
|
||||
# 1. Fetch Gerbil context if available
|
||||
if gerbil_id:
|
||||
g_data = fetch_json(f"/gerbils/{gerbil_id}")
|
||||
if g_data:
|
||||
markdown_content.append("\n### Target Gerbil Context:")
|
||||
markdown_content.append(f"- **Name**: `{g_data.get('name')}`")
|
||||
markdown_content.append(f"- **Gender**: `{g_data.get('gender')}` | **Status**: `{g_data.get('status')}`")
|
||||
markdown_content.append(f"- **DOB**: `{g_data.get('dateOfBirth') or 'None'}` | **DOD**: `{g_data.get('dateOfDeath') or 'None'}`")
|
||||
markdown_content.append(f"- **Genotype**: `{g_data.get('genotype') or 'None'}`")
|
||||
markdown_content.append(f"- **Notes**: `{g_data.get('notes') or 'None'}`")
|
||||
markdown_content.append(f"- **Import Source**: `{g_data.get('importSource')}`")
|
||||
markdown_content.append(f"- **ExternalRef**: `{g_data.get('externalRef')}`")
|
||||
|
||||
# Format Provenance history nicely if present
|
||||
prov_str = g_data.get("provenance")
|
||||
if prov_str:
|
||||
try:
|
||||
prov = json.loads(prov_str)
|
||||
markdown_content.append("- **Provenance History**:")
|
||||
for entry in prov.get("history", []):
|
||||
markdown_content.append(f" - {entry}")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
markdown_content.append(f"\n### Target Gerbil: `gerbils/{gerbil_id}` (Not found in active DB - Suppressed/Deleted)")
|
||||
|
||||
# 2. Fetch Litter context if available
|
||||
if litter_id:
|
||||
l_data = fetch_json(f"/litters/{litter_id}")
|
||||
if l_data:
|
||||
markdown_content.append("\n### Target Litter Context:")
|
||||
markdown_content.append(f"- **Litter Name**: `{l_data.get('name')}`")
|
||||
markdown_content.append(f"- **Date**: `{l_data.get('date') or 'None'}` | **Total Born**: `{l_data.get('totalBorn') or 'None'}`")
|
||||
markdown_content.append(f"- **Father ID**: `{l_data.get('fatherId') or 'None'}` | **Mother ID**: `{l_data.get('motherId') or 'None'}`")
|
||||
markdown_content.append(f"- **Notes**: `{l_data.get('notes') or 'None'}`")
|
||||
markdown_content.append(f"- **ExternalRef**: `{l_data.get('externalRef')}`")
|
||||
else:
|
||||
markdown_content.append(f"\n### Target Litter: `litters/{litter_id}` (Not found in active DB - Suppressed/Deleted)")
|
||||
|
||||
if question:
|
||||
markdown_content.append(f"\n### AI Question Asked:\n> {question.strip()}")
|
||||
|
||||
if answer:
|
||||
markdown_content.append(f"\n### Breeder's Answer:\n> **{answer.strip()}**")
|
||||
|
||||
if agent_context:
|
||||
markdown_content.append(f"\n### Internal Agent Context:\n```json\n{agent_context.strip()}\n```")
|
||||
|
||||
markdown_content.append("\n### Triage Resolution Plan:")
|
||||
# Generate some smart heuristic recommendation based on breeder response
|
||||
if status == "Answered" and answer:
|
||||
ans_lower = answer.lower()
|
||||
if "verstorben" in ans_lower or ("gestorben" in ans_lower) or any(char.isdigit() for char in answer):
|
||||
markdown_content.append("- [ ] **Action**: Update status to `Deceased`, add `dateOfDeath`, and maybe Abnehmer/receiver.")
|
||||
elif "gleiche" in ans_lower or "selbe" in ans_lower:
|
||||
markdown_content.append("- [ ] **Action**: Merge duplicate records by setting `correctDob` or aligning names.")
|
||||
elif "vater" in ans_lower or "mutter" in ans_lower:
|
||||
markdown_content.append("- [ ] **Action**: Set parents (father/mother) or inject litter override.")
|
||||
else:
|
||||
markdown_content.append("- [ ] **Action**: Apply conflict-decision resolution based on response text.")
|
||||
else:
|
||||
markdown_content.append("- [ ] **Action**: Investigate original message and check database records for appropriate override.")
|
||||
|
||||
markdown_content.append("\n---")
|
||||
|
||||
os.makedirs(os.path.dirname(output_file), exist_ok=True)
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(markdown_content) + "\n")
|
||||
|
||||
print(f"Triage report written to {output_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user