Skip to content

fix: stop the sheet push from splitting a worker's column pair - #1714

Merged
renemadsen merged 1 commit into
stablefrom
fix/sheet-push-header-pairs
Sep 17, 2026
Merged

renemadsen merged 1 commit into
stablefrom
fix/sheet-push-header-pairs

Conversation

@renemadsen

Copy link
Copy Markdown
Member

Problem

PushToGoogleSheet keeps the PlanTimer header row in step with the sites that have an assignment. It checked each half of a worker's pair with an exact, case-sensitive string comparison and appended whichever was missing on its own at the end of the row (GoogleSheetHelper.cs:94-107 on stable).

That is how tenant 1063's columns came apart. Malaika's - tekst column had gone missing, so a later push appended it at the end — after Valentin's and Phien's pairs, which had been added in between:

P  Malaika … - timer     Q  Valentin - - timer    R  Valentin - - tekst
S  Phien Van Le - timer  T  Phien Van Le - tekst  U  Malaika … - tekst

Exact matching has a second consequence: a header retyped with other spacing, other capitals or an en dash counts as absent, so the push adds a second column for a worker who already has one. Site names ending in a dash (Julius -) make that easy to trigger.

Fix

PlanTimerSheetColumns.PlanAppends plans the appends:

  • Existing headers are matched the way the import matches them — ignoring case, whitespace (NBSP included) and dash style — so a hand-edited header is recognized instead of duplicated.
  • A site with neither half gets a pair. A site with only one half gets a complete new pair, and the column left behind is named in a problem reported to the log and Sentry, so someone can move its data across and delete it.
  • Nothing is moved, renamed or removed, so no column parts company with the data underneath it.

Two further changes:

  • Only the appended cells are written. The old code rewrote the entire header row, which restated every existing header — silently reverting any header a human had corrected.
  • Appends start at the first worker column. On a sheet whose header row is empty or short, headers used to land in A/B/C, which the import skips, so the next push appended them again.

The import already pairs columns by name (#1712, #1300), so a half appended at the far end still reads correctly. This change is about not making the sheet worse, and about not duplicating columns.

Tests

PlanTimerSheetColumnsTests gains cases for: nothing to do, a new site, header variants that must not duplicate, tenant 1063's half-pair, an empty sheet, and where the first appended column lands. Pure unit tests, already in both CI shard allowlists.

Verified locally: dotnet build of TimePlanning.Pn and TimePlanning.Pn.Test. Tests run in CI.

Related

eform-backendconfiguration-plugin carries its own copy of this helper and gets the same fix, plus the missing header push when a worker is created. Consolidating the three copies (service, this plugin, bcfg) into Microting.TimePlanningBase needs a base release and is left for later.

🤖 Generated with Claude Code

PushToGoogleSheet kept the PlanTimer header row in step with the sites
that have an assignment. It looked each header up by its exact text and
appended whichever half was missing, on its own, at the end of the row.

That is how tenant 1063's columns came apart: a worker's "- tekst"
column had gone missing, so a later push appended it after two other
workers' pairs, leaving her "- timer" column six columns away. Exact
matching also meant a header retyped with other spacing, other capitals
or an en dash counted as absent, so the push added a second column for a
worker who already had one.

PlanAppends now matches existing headers the way the import does --
ignoring case, whitespace and dash style -- and a site missing a half
gets a complete new pair, with a problem naming the column left behind
so someone can move its data over and delete it. Nothing is moved,
renamed or removed, so no column parts company with its data.

Also:
- only the appended cells are written; rewriting the whole row restated
  every existing header, silently reverting one a human had corrected
- appends start at the first worker column, so they never land in the
  date columns the import skips and get appended again next time

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes align header append behavior with the import’s normalization rules, avoid destructive header rewrites, and are covered by focused unit tests for the new edge cases.

Pull request overview

This PR updates the PlanTimer Google Sheet header “push” logic to prevent a worker/site’s - timer / - tekst column pair from being split or duplicated when headers are hand-edited, and to avoid rewriting existing headers unnecessarily.

Changes:

  • Add PlanTimerSheetColumns.PlanAppends(...) to plan header appends using the same normalization rules as the import (case/whitespace/dash-insensitive matching).
  • Update PushToGoogleSheet to write only the appended header cells (not the whole header row) and to start appends at/after the first worker column.
  • Extend unit tests to cover append planning scenarios including header variants, half-pairs, and empty/short header rows.
File summaries
File Description
eFormAPI/Plugins/TimePlanning.Pn/TimePlanning.Pn/Infrastructure/Helpers/PlanTimerSheetColumns.cs Introduces PlanAppends and related helpers to plan safe, normalized header appends without reordering/moving existing columns.
eFormAPI/Plugins/TimePlanning.Pn/TimePlanning.Pn/Infrastructure/Helpers/GoogleSheetHelper.cs Switches header maintenance to PlanAppends, logs problems, and updates only the appended header range.
eFormAPI/Plugins/TimePlanning.Pn/TimePlanning.Pn.Test/PlanTimerSheetColumnsTests.cs Adds unit coverage for the new append-planning behavior and edge cases described in the PR.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@renemadsen
renemadsen merged commit 72c2a7b into stable Sep 17, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants