feat(catalog): mbox header scan, company legal-suffix match, apply order
Add --mbox-headers for Thunderbird folder files; strip GmbH/& Co. KG in CompanyGroupingKey; FindCompany falls back to full scan; apply companies before persons. Tightens role-mailbox noise filters.
This commit is contained in:
@@ -46,9 +46,12 @@ func (c *Client) GetContact(ctx context.Context, contactID string) (map[string]a
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindCompany searches for a company contact with an exact (case-insensitive)
|
// FindCompany searches for a company contact with an exact (case-insensitive)
|
||||||
// displayName match. Returns nil when not found.
|
// displayName match after slogan/legal-suffix normalization. Returns nil when not found.
|
||||||
func (c *Client) FindCompany(ctx context.Context, name string) (map[string]any, error) {
|
func (c *Client) FindCompany(ctx context.Context, name string) (map[string]any, error) {
|
||||||
needle := CompanyGroupingKey(name)
|
needle := CompanyGroupingKey(name)
|
||||||
|
if needle == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
const page = 50
|
const page = 50
|
||||||
for start := 0; ; start += page {
|
for start := 0; ; start += page {
|
||||||
items, total, err := c.ListContacts(ctx, page, start, name)
|
items, total, err := c.ListContacts(ctx, page, start, name)
|
||||||
@@ -67,6 +70,19 @@ func (c *Client) FindCompany(ctx context.Context, name string) (map[string]any,
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Search filter may miss longer legal names; fall back to a full company scan.
|
||||||
|
all, err := c.ListAllContacts(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, co := range all {
|
||||||
|
if !isCompany(co) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if CompanyGroupingKey(fmt.Sprint(co["displayName"])) == needle {
|
||||||
|
return co, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-2
@@ -10,6 +10,9 @@ var multiSpace = regexp.MustCompile(`\s+`)
|
|||||||
// sloganSeparators split a company name from a trailing tagline/slogan.
|
// sloganSeparators split a company name from a trailing tagline/slogan.
|
||||||
var sloganSeparators = []string{" — ", " – ", " - ", "—", "–"}
|
var sloganSeparators = []string{" — ", " – ", " - ", "—", "–"}
|
||||||
|
|
||||||
|
// companyLegalSuffix matches trailing legal-form tokens (GmbH, & Co. KG, …).
|
||||||
|
var companyLegalSuffix = regexp.MustCompile(`(?i)[\s,]*(&\s*co\.?\s*kg\.?|co\.?\s*kg\.?|gmbh|ag|ltd\.?|llc\.?|inc\.?|plc\.?|s\.?l\.?|sarl|b\.?v\.?)\s*$`)
|
||||||
|
|
||||||
// StripSloganSuffix returns the part before an em/en dash tagline, e.g.
|
// StripSloganSuffix returns the part before an em/en dash tagline, e.g.
|
||||||
// "Affirm — Fraud Engineering" → "Affirm".
|
// "Affirm — Fraud Engineering" → "Affirm".
|
||||||
func StripSloganSuffix(s string) string {
|
func StripSloganSuffix(s string) string {
|
||||||
@@ -22,9 +25,23 @@ func StripSloganSuffix(s string) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompanyGroupingKey normalizes a company name for dedupe (ignores slogans).
|
// StripCompanyLegalSuffix removes trailing GmbH / & Co. KG / Ltd / … tokens.
|
||||||
|
func StripCompanyLegalSuffix(s string) string {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
s = strings.TrimRight(s, ",; ")
|
||||||
|
for {
|
||||||
|
next := companyLegalSuffix.ReplaceAllString(s, "")
|
||||||
|
next = strings.TrimRight(strings.TrimSpace(next), ",; ")
|
||||||
|
if next == s || next == "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
s = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompanyGroupingKey normalizes a company name for dedupe (ignores slogans and legal suffixes).
|
||||||
func CompanyGroupingKey(s string) string {
|
func CompanyGroupingKey(s string) string {
|
||||||
return NormalizeCompanyName(StripSloganSuffix(s))
|
return NormalizeCompanyName(StripCompanyLegalSuffix(StripSloganSuffix(s)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NormalizeCompanyName lowercases and collapses whitespace for grouping.
|
// NormalizeCompanyName lowercases and collapses whitespace for grouping.
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ func TestCompanyGroupingKey(t *testing.T) {
|
|||||||
if a != b {
|
if a != b {
|
||||||
t.Fatalf("%q != %q", a, b)
|
t.Fatalf("%q != %q", a, b)
|
||||||
}
|
}
|
||||||
|
if CompanyGroupingKey("Acme") != CompanyGroupingKey("Acme GmbH & Co. KG,") {
|
||||||
|
t.Fatalf("legal suffix should not change grouping key: %q vs %q",
|
||||||
|
CompanyGroupingKey("Acme"), CompanyGroupingKey("Acme GmbH & Co. KG,"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpportunityTitlesMatchSlogan(t *testing.T) {
|
func TestOpportunityTitlesMatchSlogan(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user