fix(salary): never take a qualified salary header as the company column (#700)

* fix(salary): never take a qualified salary header as the company column

The detection loop kept the LAST header matching a company pattern, so
"Company Name | City | Company Count | Company Index" made the index
column the company column and every converted row carried
"company": "108.5"; IDA's "Firmanavn og by | Antal | Firmaets indeks"
(#615) did the same. #571's exact-match preference only helped when a
header was exactly "Company" or "Firma".

Detection is now three tiers, each taking the first match: an exact
pattern header, then a pattern header that is not a count/index column,
then any pattern header; the city column can never alias the company
column. Four new cases; the two qualified-header ones fail on master.

* changelog: place the #700 entry under [Unreleased]

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Mads Lorentzen <madslorentzen_17@hotmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
authored and GitHub committed 2026-10-21 07:12:41 +02:00
1 parent 217206f9db
commit 58a4ec0468
3 files changed
+109 -13

No files matched your search

+75
View File
@@ -542,6 +542,81 @@ class BareCountIndexPairingTests(unittest.TestCase):
self.assertNotRegex(rendered, r"^\s*Count\s+500", )
class QualifiedCompanyHeaderNextToQualifiedSalaryHeader(unittest.TestCase):
"""A name header must win over a salary header that also carries the word.
The detection loop kept the LAST header matching a company pattern, so
"Company Name | City | Company Count | Company Index" made the index
column the company column and every row's company read "108.5". #571
added an exact-match preference, which only helps when a header is
exactly "Company"; the qualified name header stayed exposed. The Danish
case below is a constructed header in the same shape, not the IDA
workbook, whose pairs are headed "Antal" and "Indeks" and already convert.
"""
def test_company_name_wins_over_company_index(self):
ws = FakeWorksheet([
("Company Name", "City", "Company Count", "Company Index"),
("Acme Corp", "Berlin", 25, 108.5),
])
entry = parse_sheet(ws)[0]
self.assertEqual(entry["company"], "Acme Corp")
self.assertEqual(entry["city"], "Berlin")
self.assertEqual(entry["categories"], {"company": {"count": 25, "index": 108.5}})
def test_danish_name_header_wins_over_qualified_index_header(self):
# The cell carries no comma so the case tests which column wins and
# does not depend on how a combined name-and-city cell is split (#660).
ws = FakeWorksheet([
("Firmanavn og by", "Antal", "Firmaets indeks"),
("Acme A/S", 25, 108.5),
])
entry = parse_sheet(ws)[0]
self.assertEqual(entry["company"], "Acme A/S")
self.assertEqual(sum(1 for c in entry["categories"].values() if c.get("index") == 108.5), 1)
self.assertEqual(sum(1 for c in entry["categories"].values() if c.get("count") == 25), 1)
def test_exact_header_still_wins_over_a_qualified_name_header(self):
# Tier 1 (#571) is unchanged: "Company" beats "Company Name" wherever it sits.
ws = FakeWorksheet([
("Company Name", "Company", "Salary Index"),
("Acme Corp (legal)", "Acme", 108.5),
])
self.assertEqual(parse_sheet(ws)[0]["company"], "Acme")
def test_city_column_never_aliases_the_company_column(self):
# "Firmanavn og by" carries both a company and a city pattern word.
ws = FakeWorksheet([
("Firmanavn og by", "Antal", "Indeks"),
("Acme A/S", 25, 108.5),
])
entry = parse_sheet(ws)[0]
self.assertEqual(entry["company"], "Acme A/S")
self.assertEqual(entry["city"], "")
self.assertEqual(entry["categories"], {"all_employees": {"count": 25, "index": 108.5}})
def test_combined_header_before_a_real_city_column_keeps_the_city(self):
# The city lookup must skip the company column: with the combined
# header first, the first city-pattern match used to land on it and
# was then cleared, dropping a real city column that followed.
for headers, row, city in (
(("Company and city", "City name", "Count", "Index"), ("Acme Corp", "Berlin", 25, 108.5), "Berlin"),
(("Firmanavn og by", "City name", "Antal", "Indeks"), ("Acme A/S", "Aarhus", 25, 108.5), "Aarhus"),
):
with self.subTest(headers=headers):
entry = parse_sheet(FakeWorksheet([headers, row]))[0]
self.assertEqual(entry["company"], row[0])
self.assertEqual(entry["city"], city)
self.assertEqual(entry["categories"], {"all_employees": {"count": 25, "index": 108.5}})
class CompoundCategoryPairingTests(unittest.TestCase):
def test_parse_sheet_pairs_danish_compound_index_with_count(self):
# "Lønindeks alle" is *detected* as an index column via