fix: decode BC OData enum encoding so G/L Account lines show in cost breakdowns#212
Merged
Merged
Conversation
…downs BC's OData serializer URL-encodes named enum values, so a planning line of type "G/L Account" arrives as "G_x002F_L_x0020_Account". Thyme compared the raw value against the plain "G/L Account" string, so G/L Account planning lines never matched and their amounts showed as 0 in the Budget Cost and Billable Price per-type breakdowns on the project details page (confirmed against live BC for PR00100 task 9999). Add decodeBCEnum() to decode the _xHHHH_ escapes generically and apply it to type/lineType once at the fetch boundary in bcClient, so all downstream comparisons use the plain values. Fixes #211 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes missing G/L Account Job Planning Lines in the project details cost breakdowns by decoding Business Central’s OData enum escaping (e.g. G_x002F_L_x0020_Account → G/L Account) so downstream comparisons operate on plain values.
Changes:
- Added a generic
decodeBCEnum()helper to decode BC_xHHHH_enum escapes. - Normalized
typeandlineTypeinbcClientwhen fetching job planning lines (decode at the boundary). - Added unit tests covering the production-confirmed encoded enum values.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/utils/unitConversion.ts |
Introduces decodeBCEnum() used to normalize BC enum strings. |
src/services/bc/bcClient.ts |
Decodes planning-line type/lineType during fetch to fix downstream matching. |
tests/unit/utils/unitConversion.test.ts |
Adds unit tests validating enum decoding behavior (including production example). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- decodeBCEnum: scan left-to-right with a sticky regex so a literal underscore escape (_x005F_) is consumed as one unit and a following escape sequence is left intact, rather than re-read. Add tests for the _x005F_ and adjacent-escape cases. - normalizePlanningLines: narrow decoded type/lineType against the known unions and fall back to the original value when unrecognized, instead of a blind cast that could mask unexpected BC enums. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BenGWeeks
approved these changes
Jun 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Job Planning Lines of Type = G/L Account were not appearing in the Budget Cost and Billable Price per-type breakdowns on the project details page — the G/L Account row always showed £0.
Root cause: BC's OData serializer URL-encodes named enum values, so
type"G/L Account" arrives over the wire asG_x002F_L_x0020_Account(/→_x002F_, space →_x0020_). Thyme compared the raw value against the plain'G/L Account'string, so these lines never matched. (The same encoding was already handled forlineTypebut not fortype.)Confirmed against live production BC —
/jobPlanningLinesfor PR00100 task 9999 returns:{ "lineType": "Budget", "type": "G_x002F_L_x0020_Account", "totalCost": 500 } { "lineType": "Billable", "type": "G_x002F_L_x0020_Account", "totalPrice": 24000 }Changes
src/utils/unitConversion.ts— adddecodeBCEnum(), which generically decodes BC's_xHHHH_enum escapes (not hardcoded to one value — decodes whatever BC sends).src/services/bc/bcClient.ts— decodetypeandlineTypeonce at the fetch boundary (getJobPlanningLinesandgetJobPlanningLinesForWeek), so all downstream comparisons use the plain values.tests/unit/utils/unitConversion.test.ts— 4 new tests covering the exact wire value confirmed from production.Test plan
/jobPlanningLines, PR00100 task 9999)bun run test— 37/37 unit tests pass (incl. newdecodeBCEnumcases)bun run typecheck— cleanbun run lint— 0 errorsbun run build— succeedsFixes #211
🤖 Generated with Claude Code