fix(convert_salary_excel): store standalone count columns as counts, not indexes (#230)

An unmatched count column (e.g. a lone total headcount with no paired index
column) was appended as an untyped standalone value and stored under "index",
even though detect_column_type had already classified it as a count.
salary_lookup then rendered the raw headcount as a salary index with a
meaningless "vs baseline" percentage.

Tag unmatched count columns with field="count" so the row parser stores them
under "count" (as an int, matching the paired-count branch). Standalone index
and untyped columns are unaffected.
This commit is contained in:
Johnson K C
2026-07-23 10:32:22 +02:00
committed by GitHub
parent 1ae66ad094
commit aa7c707399
2 changed files with 24 additions and 3 deletions
+16
View File
@@ -169,6 +169,22 @@ class DetectColumnTypeTests(unittest.TestCase):
self.assertEqual(categories["kvinder"], {"count": 15, "index": 95.0}) self.assertEqual(categories["kvinder"], {"count": 15, "index": 95.0})
self.assertEqual(categories["mænd"], {"count": 20, "index": 108.0}) self.assertEqual(categories["mænd"], {"count": 20, "index": 108.0})
def test_standalone_count_column_is_stored_as_count_not_index(self):
# A count column with no matching index column (e.g. a lone total
# headcount) is still count data. It must not be emitted as a salary
# index, which salary_lookup would render with a bogus "vs baseline"
# percentage. The paired category alongside it is unaffected.
ws = FakeWorksheet([
("Company", "Antal", "IT Count", "IT Index"),
("Example Corp", 250, 30, 108.5),
])
companies = parse_sheet(ws)
categories = companies[0]["categories"]
self.assertEqual(categories["antal"], {"count": 250})
self.assertEqual(categories["it"], {"count": 30, "index": 108.5})
def test_parse_sheet_non_adjacent_columns_no_cross_match(self): def test_parse_sheet_non_adjacent_columns_no_cross_match(self):
ws = FakeWorksheet([ ws = FakeWorksheet([
("Company", "Count_A", "Count_B", "Index_A", "Index_B"), ("Company", "Count_A", "Count_B", "Index_A", "Index_B"),
+8 -3
View File
@@ -168,10 +168,14 @@ def parse_sheet(ws, sheet_label=None):
used_indexes.add(ii) used_indexes.add(ii)
break break
# Remaining unmatched count columns become standalone (use original header) # Remaining unmatched count columns become standalone. They are still count
# data, so tag them as such — otherwise a lone headcount would be emitted as
# a salary index and rendered with a meaningless "vs baseline" percentage.
for ci, (c_idx, c_header, _) in enumerate(count_cols): for ci, (c_idx, c_header, _) in enumerate(count_cols):
if ci not in used_counts: if ci not in used_counts:
categories.append({"name": c_header.lower().replace(" ", "_"), "value_col": c_idx}) categories.append(
{"name": c_header.lower().replace(" ", "_"), "value_col": c_idx, "field": "count"}
)
# Remaining unmatched index columns become standalone (use original header) # Remaining unmatched index columns become standalone (use original header)
for ii, (i_idx, i_header, _) in enumerate(index_cols): for ii, (i_idx, i_header, _) in enumerate(index_cols):
@@ -226,7 +230,8 @@ def parse_sheet(ws, sheet_label=None):
# Non-numeric standalone value (e.g. a free-text "Notes" # Non-numeric standalone value (e.g. a free-text "Notes"
# column) is not salary data; skip it for this row. # column) is not salary data; skip it for this row.
continue continue
entry["categories"][cat_name] = {"index": val} field = cat.get("field", "index")
entry["categories"][cat_name] = {field: int(val) if field == "count" else val}
companies.append(entry) companies.append(entry)