feat(import): RPRO3-Dubletten-Entscheidungen der Züchterin als Override
Manuelle "gleich/verschieden?"-Entscheidungen aus den rpro3-import-Tickets fließen jetzt in den RennmausPro-III-Import ein: - Rpro3Decisions (Modell + JSON-Loader): same (Force-Merge), different (Force-Split), fields (Farbe/DOB/Herkunft/resident/Notiz). Schlüssel = rid. - Rpro3Dedup.Run(animals, decisions): honoriert die Overrides nach dem automatischen Dedup (eine rid zieht ihren Cluster mit). - Rpro3ImportService: lädt Import/Rpro3/rpro3-decisions.json, wendet Feld-Overrides im Plan-Builder an. - rpro3-decisions.json: 14 bestätigte Entscheidungen (Eiji, Momo, Samuel, Female, Kennedy, Fegur, Tuli, Bura, Mister X, Zoey, Max, Akiro, Merlin, Snickers). - tools/import/rpro3_lookup.py: Triage-Helfer (Farbe/Gencode/Eltern/ Nachzucht+Partner aus _rpro3.db) für die Rückfragen an die Züchterin. - 4 neue Tests (Force-Merge/Force-Split/Loader); Suite 268 grün. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -65,9 +65,19 @@ namespace GerbilManagerWebAPI.Import.Rpro3
|
||||
return UnknownValues.Contains(v) ? "" : v;
|
||||
}
|
||||
|
||||
public static DedupResult Run(IReadOnlyList<Rpro3Animal> animals)
|
||||
public static DedupResult Run(IReadOnlyList<Rpro3Animal> animals) => Run(animals, null);
|
||||
|
||||
/// <summary>
|
||||
/// Wie <see cref="Run(IReadOnlyList{Rpro3Animal})"/>, berücksichtigt aber manuelle
|
||||
/// Entscheidungen der Züchterin (<paramref name="decisions"/>): „Different"-Gruppen
|
||||
/// verhindern automatisches Zusammenlegen, „Same"-Gruppen erzwingen ein Merge über
|
||||
/// Varianten hinweg (jede rid zieht ihren ganzen Auto-Cluster mit).
|
||||
/// </summary>
|
||||
public static DedupResult Run(IReadOnlyList<Rpro3Animal> animals, Rpro3Decisions? decisions)
|
||||
{
|
||||
var result = new DedupResult();
|
||||
decisions ??= Rpro3Decisions.Empty;
|
||||
var splitGroup = decisions.BuildSplitGroups();
|
||||
|
||||
foreach (var a in animals)
|
||||
{
|
||||
@@ -123,12 +133,31 @@ namespace GerbilManagerWebAPI.Import.Rpro3
|
||||
for (int j = i + 1; j < group.Count; j++)
|
||||
{
|
||||
var a = group[i]; var b = group[j];
|
||||
// Force-Split: von der Züchterin als verschieden markierte Tiere nie zusammenlegen.
|
||||
if (splitGroup.TryGetValue(a.Rid, out var ga) && splitGroup.TryGetValue(b.Rid, out var gb) && ga != gb)
|
||||
continue;
|
||||
bool comp = CompatDob(a.Dob, b.Dob) && Compat(a.FarbeKey, b.FarbeKey) && Compat(a.OriginKey, b.OriginKey);
|
||||
if (comp && Positive(a, b) >= 1 && Conflict(a, b) == 0)
|
||||
Union(a.Rid, b.Rid);
|
||||
}
|
||||
}
|
||||
|
||||
// Force-Merge: von der Züchterin als dasselbe Tier bestätigte Varianten zusammenlegen
|
||||
// (eine rid je Variante genügt — Find/Union zieht den ganzen Auto-Cluster mit). Nur rids,
|
||||
// die es im Datensatz auch gibt, werden berücksichtigt.
|
||||
var knownRids = new HashSet<string>(animals.Select(a => a.Rid), StringComparer.Ordinal);
|
||||
foreach (var grp in decisions.SameGroups())
|
||||
{
|
||||
string? anchor = null;
|
||||
foreach (var rid in grp)
|
||||
{
|
||||
if (!knownRids.Contains(rid)) continue;
|
||||
parent.TryAdd(rid, rid);
|
||||
if (anchor is null) anchor = rid;
|
||||
else Union(anchor, rid);
|
||||
}
|
||||
}
|
||||
|
||||
// Cluster sammeln
|
||||
var clusters = new Dictionary<string, List<Rpro3Animal>>();
|
||||
foreach (var a in animals)
|
||||
|
||||
Reference in New Issue
Block a user