diff --git a/src/RealCV.Infrastructure/Services/CompanyVerifierService.cs b/src/RealCV.Infrastructure/Services/CompanyVerifierService.cs index e06937f..0b467b4 100644 --- a/src/RealCV.Infrastructure/Services/CompanyVerifierService.cs +++ b/src/RealCV.Infrastructure/Services/CompanyVerifierService.cs @@ -141,6 +141,7 @@ public sealed class CompanyVerifierService : ICompanyVerifierService ["Revolut"] = new[] { "REVOLUT LTD", "REVOLUT LIMITED" }, ["Monzo"] = new[] { "MONZO BANK LIMITED" }, ["Starling Bank"] = new[] { "STARLING BANK LIMITED" }, + ["Deliveroo"] = new[] { "ROOFOODS LTD", "DELIVEROO HOLDINGS PLC" }, // Travel & Hospitality ["Thomas Cook"] = new[] { "THOMAS COOK GROUP PLC", "THOMAS COOK UK LIMITED" }, @@ -182,6 +183,7 @@ public sealed class CompanyVerifierService : ICompanyVerifierService ["JLR"] = new[] { "JAGUAR LAND ROVER LIMITED" }, ["Rolls-Royce"] = new[] { "ROLLS-ROYCE PLC", "ROLLS-ROYCE HOLDINGS PLC" }, ["BMW UK"] = new[] { "BMW (UK) LIMITED", "BMW GROUP UK LIMITED" }, + ["JCB"] = new[] { "J.C. BAMFORD EXCAVATORS LIMITED", "J. C. BAMFORD LIMITED" }, // Food & Beverage ["Unilever"] = new[] { "UNILEVER PLC" }, @@ -828,6 +830,7 @@ public sealed class CompanyVerifierService : ICompanyVerifierService /// /// Checks if any candidate directly matches a known trading name alias. /// This allows bypassing AI matching for known aliases where the AI might incorrectly reject. + /// Prefers active companies over dissolved ones when multiple matches exist. /// private static (CompaniesHouseSearchItem Item, int Score)? FindDirectAliasMatch( string companyName, @@ -842,9 +845,12 @@ public sealed class CompanyVerifierService : ICompanyVerifierService return null; } - // Look for candidates that exactly match one of the known aliases - foreach (var alias in aliases) + // Collect all matching candidates, then pick the best one + var matchingCandidates = new List<(CompaniesHouseSearchItem Item, int AliasIndex)>(); + + for (var aliasIndex = 0; aliasIndex < aliases.Length; aliasIndex++) { + var alias = aliases[aliasIndex]; var aliasUpper = alias.ToUpperInvariant(); foreach (var candidate in candidates) @@ -858,22 +864,33 @@ public sealed class CompanyVerifierService : ICompanyVerifierService var fuzzyScore = Fuzz.Ratio(aliasUpper, titleUpper); if (fuzzyScore >= 95) { - // Verify the company existed at the claimed start date - if (claimedStartDate.HasValue) - { - var incDate = DateHelpers.ParseDate(candidate.DateOfCreation); - if (incDate.HasValue && incDate.Value > claimedStartDate.Value) - { - continue; // Company didn't exist yet - } - } - - return (candidate, 100); // 100% match via known alias + matchingCandidates.Add((candidate, aliasIndex)); } } } - return null; + if (matchingCandidates.Count == 0) + return null; + + // Sort candidates: prefer active > dissolved, then by alias order (first alias is preferred) + var bestMatch = matchingCandidates + .OrderBy(m => m.Item.CompanyStatus?.ToLowerInvariant() == "active" ? 0 : 1) // Active first + .ThenBy(m => m.Item.CompanyStatus?.ToLowerInvariant() == "dissolved" ? 1 : 0) // Dissolved last + .ThenBy(m => m.AliasIndex) // First alias is preferred + .First(); + + // Verify the company existed at the claimed start date + if (claimedStartDate.HasValue) + { + var incDate = DateHelpers.ParseDate(bestMatch.Item.DateOfCreation); + if (incDate.HasValue && incDate.Value > claimedStartDate.Value) + { + // Company didn't exist yet - but still return it so the flag can be raised + // Don't skip, let the verification process handle the date issue + } + } + + return (bestMatch.Item, 100); // 100% match via known alias } private async Task FindCachedMatchAsync(string companyName) diff --git a/tools/CVBatchTester/Program.cs b/tools/CVBatchTester/Program.cs index dc6c4fa..2697428 100644 --- a/tools/CVBatchTester/Program.cs +++ b/tools/CVBatchTester/Program.cs @@ -198,6 +198,16 @@ class Program if (!string.IsNullOrEmpty(result.VerificationNotes)) Log($" Note: {result.VerificationNotes}"); + + // Display any flags (warnings/issues) + if (result.Flags?.Count > 0) + { + foreach (var flag in result.Flags) + { + var flagIcon = flag.Severity == "Critical" ? "⚠️" : "ℹ️"; + Log($" {flagIcon} FLAG [{flag.Type}]: {flag.Message}"); + } + } } catch (Exception ex) {