Repository navigation
Conversation
…t for the lightning bolt Co-authored-by: thelullabyy <[email protected]>
|
I created this PR from an upstream branch since I don't have push access to your fork. To take ownership of this branch and be able to push updates, run: Then you can close this PR and open a new one from your fork. |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
|
🤖 Android test steps verification results: ✅ pass On Android, GB government rates were auto-generated with the lightning bolt, and turning on Track tax and regenerating the rates caused no errors. The bolt stayed through every Tax reclaimable edit, and no JS errors or redboxes appeared. As on Web, only the standard GB (AMAP) rates appeared, never fuel bands, and logs weren't streamed, so the console check relies on no visible errors.
|
|
@MelvinBot Please replace all |
|
@thelullabyy Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
Done. I updated the PR description and marked the PR ready for review.
Earlier dev-environment runs showed only AMAP rates, so you may need staging to see the fuel-band rows. I left Offline tests and Screenshots/Videos empty for you to fill in. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / SafariScreen.Recording.2026-10-20.at.00.13.18.movScreen.Recording.2026-10-20.at.00.16.20.mov |
thelullabyy
left a comment
There was a problem hiding this comment.
Overall the logic looks good to me. A few comments inline.
One small thing in the PR description: Tests step 17 says to set a tax rate on a Great Britain rate on the AMAP workspace from step 1, but that workspace has Taxes / Track tax off, so the tax rate and Tax reclaimable on fields aren't available there. Can you update that step (e.g. turn on Taxes but leave Track tax off, or remove it)?
|
|
||
| if (shouldAutoUpdateGovernmentDistanceRates && customUnit) { | ||
| const copiedSourceRateIDs = new Set(Object.values(customUnit.rates ?? {}).map((rate) => rate.attributes?.governmentRate?.sourceRateID)); | ||
| const shouldUseFuelBandRates = isTaxTrackingEnabled(true, policy, true); |
There was a problem hiding this comment.
This is only evaluated when auto-update is turned on. What happens if a GBP workspace already has auto-update on with the AMAP rates and the admin then turns on Track tax (or turns it off on a workspace that has the bands)? enableDistanceRequestTax doesn't touch the rates, so optimistically nothing changes.
Does the server swap AMAP <-> fuel bands when distance tax is toggled? If it does, we should mirror that optimistically in enableDistanceRequestTax (and the policy Taxes toggle). If it doesn't, the workspace stays on AMAP after enabling tax, which seems to go against the goal here. Either way, can we add a test step covering this order (auto-update first, Track tax second)?
There was a problem hiding this comment.
Good catch. The server does handle this order, but this PR doesn't mirror it optimistically, on purpose.
- Turning tax on: when turning on distance tax (or turning tax tracking back on) makes a GBP auto-update workspace eligible, the server adds the missing fuel-band rates. It doesn't remove the existing AMAP rates. Mirroring that in
enableDistanceRequestTaxandenablePolicyTaxesis the follow-up [HOLD #104135] Optimistic UK fuel-band rates when turning on tax, which is on hold for this PR and reusesbuildOnyxDataForGovernmentRateAutoUpdate. - Turning tax off: nothing is swapped. Existing fuel-band rates stay, the same way auto-update never modifies existing rates.
I added a "Turning on tax after auto-update" block to Tests and QA (steps 17–19): on the AMAP workspace, turn on Taxes and Track tax, then check the AMAP rates are unchanged and keep the bolt. That also fixes the old step 17, which set a tax rate while tax was off.
|
|
||
| /** Whether a government rate is a UK fuel band, whose series carries the band after the country code. */ | ||
| function isFuelBandGovernmentRate(sourceRateID: string): boolean { | ||
| return getGovernmentRateSeries(sourceRateID) !== sourceRateID.split('_').at(0); |
There was a problem hiding this comment.
NAB: this computes the series and splits the ID again just to check whether there is a segment between the country and the date. Could be simpler and easier to read:
return sourceRateID.split('_').length > 2;There was a problem hiding this comment.
Done in edc5108: isFuelBandGovernmentRate now returns sourceRateID.split('_').length > 2. Results don't change: GB_2026-04-06 has 2 parts and band IDs have more.
|
@MelvinBot Please update your PR based on above reviews |
Co-authored-by: thelullabyy <[email protected]>
|
@thelullabyy @neil-marcellini One of you needs to copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
I updated the PR based on your review.
Typecheck, ESLint on the changed file, and 309 Jest tests in |
|
The failing check is unrelated to this PR. No code fix is needed. Please rerun the failed Bun tests job. Analysis: One CI tooling test failed: Evidence: This PR changes only distance-rate code and its tests ( The other two failures, |
|
I merged
|














Explanation of Change
The UK publishes fuel-band mileage rates alongside its standard (AMAP) rate. The server will copy the bands, with their VAT-reclaimable fraction, only to workspaces that track tax and have distance tax on, and AMAP to every other workspace. The App's optimistic copy didn't know about bands, so it would have added AMAP plus every band, without the fraction. The lightning bolt also ignored the reclaimable amount, so an edited band still looked auto-generated.
GovernmentMileageRateandGovernmentRateSnapshotget an optionaltaxClaimablePercentage.buildOnyxDataForGovernmentRateAutoUpdateusesisTaxTrackingEnabled(true, policy, true)asshouldUseFuelBandRates. For GB rates only, it copies the bands when that is true and the standard rate otherwise. Other countries are unaffected.getGovernmentRateSeriesstrips the trailing_<startDate>withlastIndexOf('_'), so band IDs likeGB_PETROL_UP_TO_1400_2026-06-01(whose band names contain_) resolve toGB_PETROL_UP_TO_1400.taxClaimablePercentagegoes on the rate and its snapshot when the reference rate has one.enabledcomes from the previous rate in the same series, including rates copied earlier in the same request, and falls back to the reference rate's value.taxRateExternalIDis left to the server response.buildOnyxDataForGovernmentRateAutoUpdateandsetWorkspaceDistanceAutoUpdatenow takepolicyinstead ofpolicyID+customUnit, which are derived inside. All callers already hadpolicy.isGovernmentRateUnmodifiedalso compares the reclaimable amount at the 4-decimal precision the edit page shows. Re-entering the shown value therefore brings the bolt back. Snapshots without a fraction, such as US/EUR rates, ignore it as before. The edit page now uses the samegetTaxClaimableDisplayAmounthelper, and itsuseCallbackwas removed so React Compiler can still compile the component.Note: the
enabledinheritance applies to every country's copied rates, matching the server's shared copy. A GBP currency change without a country still copies nothing optimistically; the server copies the bands and its response adds them.AI tests run by MelvinBot:
npm run typecheck,npm run lint-changed,npm run fmt,npm run spell-changed,react-compiler-compliance-checkon the changed pages, and Jest forDistanceRateTest,PolicyDistanceRatesUtilsTest,PolicyTest,PolicyUtilsTest,WorkspaceOverviewCurrencyPageTest,WorkspaceUpgradeTest,IOURequestStepDistanceRateTestand the distance-rate hook tests (all passed). The full Jest suite and the Storybook smoke test were not run locally.Fixed Issues
$ #104135
PROPOSAL: #104135 (comment)
Tests
Standard (AMAP) rates — workspace without distance tax
Fuel-band rates — workspace with distance tax
These steps need the server to publish GB fuel-band reference rates. Until it does, only the standard rates appear.
6. Create another Control workspace and set its default currency to GBP.
7. Go to Workspace > More features and turn on Distance rates and Taxes.
8. Go to Distance rates > Settings and turn on Track tax.
9. In the same Settings page, turn on Auto-update government rate.
10. Go back to Distance rates. Verify the Great Britain fuel-band rates are added (one rate per fuel type / engine size band), each with the lightning bolt.
11. Verify the standard Great Britain (AMAP) rate is not added.
Lightning bolt and tax reclaimable
12. Open one of the fuel-band rates and note the Tax reclaimable on amount.
13. Change the Tax reclaimable on amount to a different value and save.
14. Verify the lightning bolt no longer shows for that rate.
15. Open the same rate, set Tax reclaimable on back to the amount from step 12, and save.
16. Verify the lightning bolt shows again for that rate.
Turning on tax after auto-update
17. On the workspace from step 1, go to More features and turn on Taxes. Then go to Distance rates > Settings and turn on Track tax.
18. Go back to Distance rates. Verify the existing Great Britain (AMAP) rates are unchanged and still show the lightning bolt. Adding fuel-band rates at this point is out of scope here and tracked in [HOLD #104135] Optimistic UK fuel-band rates when turning on tax.
19. Open one of these AMAP rates, set a tax rate, change its Tax reclaimable on amount, and save. Verify the lightning bolt still shows (AMAP rates ignore the reclaimable amount).
Offline tests
QA Steps
Standard (AMAP) rates — workspace without distance tax
Fuel-band rates — workspace with distance tax
These steps need the server to publish GB fuel-band reference rates. Until it does, only the standard rates appear.
6. Create another Control workspace and set its default currency to GBP.
7. Go to Workspace > More features and turn on Distance rates and Taxes.
8. Go to Distance rates > Settings and turn on Track tax.
9. In the same Settings page, turn on Auto-update government rate.
10. Go back to Distance rates. Verify the Great Britain fuel-band rates are added (one rate per fuel type / engine size band), each with the lightning bolt.
11. Verify the standard Great Britain (AMAP) rate is not added.
Lightning bolt and tax reclaimable
12. Open one of the fuel-band rates and note the Tax reclaimable on amount.
13. Change the Tax reclaimable on amount to a different value and save.
14. Verify the lightning bolt no longer shows for that rate.
15. Open the same rate, set Tax reclaimable on back to the amount from step 12, and save.
16. Verify the lightning bolt shows again for that rate.
Turning on tax after auto-update
17. On the workspace from step 1, go to More features and turn on Taxes. Then go to Distance rates > Settings and turn on Track tax.
18. Go back to Distance rates. Verify the existing Great Britain (AMAP) rates are unchanged and still show the lightning bolt.
19. Open one of these AMAP rates, set a tax rate, change its Tax reclaimable on amount, and save. Verify the lightning bolt still shows.
Regression — other countries
20. Create a Control workspace in USD, turn on Distance rates, and turn on Auto-update government rate.
21. Verify the United States government rates are added with the lightning bolt, as before.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari