From aa7c7073990492c9111fbdda48f6adde24a1d91b Mon Sep 17 00:00:00 2001 From: Johnson K C Date: Thu, 23 Jul 2026 01:32:22 -0700 Subject: [PATCH] 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. --- tests/test_convert_salary_excel.py | 16 ++++++++++++++++ tools/convert_salary_excel.py | 11 ++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/test_convert_salary_excel.py b/tests/test_convert_salary_excel.py index 0c03097..54e944c 100644 --- a/tests/test_convert_salary_excel.py +++ b/tests/test_convert_salary_excel.py @@ -169,6 +169,22 @@ class DetectColumnTypeTests(unittest.TestCase): self.assertEqual(categories["kvinder"], {"count": 15, "index": 95.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): ws = FakeWorksheet([ ("Company", "Count_A", "Count_B", "Index_A", "Index_B"), diff --git a/tools/convert_salary_excel.py b/tools/convert_salary_excel.py index 8ff5573..49c67c1 100644 --- a/tools/convert_salary_excel.py +++ b/tools/convert_salary_excel.py @@ -168,10 +168,14 @@ def parse_sheet(ws, sheet_label=None): used_indexes.add(ii) 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): 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) 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" # column) is not salary data; skip it for this row. 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)