Skip to content

Commit 2a373f1

Browse files
committed
Merge branch 'main' into fix/60657
2 parents a19159a + bd59655 commit 2a373f1

File tree

185 files changed

+3873
-1689
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

185 files changed

+3873
-1689
lines changed

.github/actions/composite/announceFailedWorkflowInSlack/action.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ inputs:
1313
runs:
1414
using: composite
1515
steps:
16-
- uses: 8398a7/action-slack@v3
16+
- uses: 8398a7/action-slack@1750b5085f3ec60384090fb7c52965ef822e869e
1717
name: Job failed Slack notification
1818
with:
1919
status: custom

.github/actions/composite/setupNode/action.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ runs:
2323
shell: bash
2424
run: jq 'del(.version, .packages[""].version)' package-lock.json > normalized-package-lock.json
2525

26-
- uses: actions/setup-node@v4
26+
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e #v4
2727
with:
2828
node-version-file: '.nvmrc'
2929
cache: npm

.github/workflows/androidBump.yml

+20-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ on:
99
jobs:
1010
android_bump:
1111
runs-on: ubuntu-latest
12-
1312
steps:
14-
- uses: actions/checkout@v4
13+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
1514

1615
- name: Setup Node
1716
uses: ./.github/actions/composite/setupNode
@@ -47,3 +46,22 @@ jobs:
4746
echo "HALTED: ${{ steps.checkAndroidStatus.outputs.HALTED }}"
4847
echo "ROLLOUT_PERCENTAGE: ${{ steps.checkAndroidStatus.outputs.ROLLOUT_PERCENTAGE }}"
4948
bundle exec fastlane android update_hybrid_rollout rollout:${{ steps.checkAndroidStatus.outputs.ROLLOUT_PERCENTAGE }}
49+
50+
- name: Warn deployers if Android rollout percentage could not be updated
51+
if: ${{ failure() }}
52+
# v3
53+
uses: 8398a7/action-slack@1750b5085f3ec60384090fb7c52965ef822e869e
54+
with:
55+
status: custom
56+
custom_payload: |
57+
{
58+
channel: '#deployer',
59+
attachments: [{
60+
color: "#DB4545",
61+
pretext: `<!subteam^S4TJJ3PSL>`,
62+
text: `💥 Android rollout percentage could not be updated. <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run> 💥`,
63+
}]
64+
}
65+
env:
66+
GITHUB_TOKEN: ${{ github.token }}
67+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

.github/workflows/deploy.yml

+21-6
Original file line numberDiff line numberDiff line change
@@ -201,18 +201,33 @@ jobs:
201201
env:
202202
BROWSERSTACK: ${{ secrets.BROWSERSTACK }}
203203

204+
- name: Install bundletool
205+
run: |
206+
readonly BUNDLETOOL_VERSION="1.18.1"
207+
readonly BUNDLETOOL_URL="https://github.com/google/bundletool/releases/download/${BUNDLETOOL_VERSION}/bundletool-all-${BUNDLETOOL_VERSION}.jar"
208+
209+
# Download jar from GitHub Release
210+
curl -L -o bundletool.jar "$BUNDLETOOL_URL"
211+
212+
# Validate checksum
213+
readonly EXPECTED_SHA="675786493983787ffa11550bdb7c0715679a44e1643f3ff980a529e9c822595c"
214+
SHA="$(sha256sum bundletool.jar | cut -d ' ' -f1)"
215+
if [[ "$SHA" != "$EXPECTED_SHA" ]]; then
216+
echo "SHA mismatch: expected $EXPECTED_SHA but got $ACTUAL_SHA"
217+
exit 1
218+
fi
219+
204220
- name: Generate APK from AAB
205221
run: |
206-
json=$(curl -s https://api.github.com/repos/google/bundletool/releases/latest)
207-
downloadUrl=$(echo "$json" | jq -r ".assets | .[].browser_download_url")
208-
curl "$downloadUrl" -4 -sL -o 'bundletool.jar'
222+
# Generate apks using bundletool
209223
java -jar bundletool.jar build-apks --bundle=${{ env.aabPath }} --output=Expensify.apks \
210224
--mode=universal \
211225
--ks=upload-key.keystore \
212226
--ks-pass=pass:${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_PASSWORD }} \
213227
--ks-key-alias=${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEYSTORE_ALIAS }} \
214228
--key-pass=pass:${{ steps.load-credentials.outputs.ANDROID_UPLOAD_KEY_PASSWORD }}
215-
229+
230+
# Unzip just the universal apk
216231
unzip -p Expensify.apks universal.apk > Expensify.apk
217232
218233
- name: Upload Android APK build artifact
@@ -254,7 +269,7 @@ jobs:
254269
attachments: [{
255270
color: "#DB4545",
256271
pretext: `<!subteam^S4TJJ3PSL>`,
257-
text: `💥 Android HybridApp production deploy failed. No need to do anything, Jules will <https://stackoverflowteams.com/c/expensify/questions/5738|manually submit> ${{ needs.prep.outputs.APP_VERSION }} in the <https://play.google.com/console/u/0/developers/8765590895836334604/app/4974129597497161901/releases/overview|Google Play Store>. 💥`,
272+
text: `💥 Android HybridApp production <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|deploy run> failed. Please <https://stackoverflowteams.com/c/expensify/questions/5738|manually submit> ${{ needs.prep.outputs.APP_VERSION }} in the <https://play.google.com/console/u/0/developers/8765590895836334604/app/4974129597497161901/releases/overview|Google Play Store>. 💥 But first check the workflow, it's likely that the release was successful and <https://github.com/Expensify/Expensify/issues/488492|this error> is occuring)`,
258273
}]
259274
}
260275
env:
@@ -623,7 +638,7 @@ jobs:
623638
gh release create ${{ needs.prep.outputs.TAG }} ${{ github.ref == 'refs/heads/staging' && '--prerelease' || '' }} \
624639
--repo ${{ github.repository }} \
625640
--title ${{ needs.prep.outputs.TAG }} \
626-
--notes-start-tag ${{ steps.get_last_prod_version.outputs.LAST_PROD_VERSION }} \
641+
${{ github.ref == 'refs/heads/production' && format('--notes-start-tag {0}', steps.get_last_prod_version.outputs.LAST_PROD_VERSION) || '' }} \
627642
--generate-notes \
628643
--verify-tag \
629644
--target ${{ github.ref }}

.github/workflows/e2ePerformanceTests.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
DELTA_REF: ${{ steps.getDeltaRef.outputs.DELTA_REF }}
2929
IS_PR_MERGED: ${{ steps.getPullRequestDetails.outputs.IS_MERGED }}
3030
steps:
31-
- uses: actions/checkout@v4
31+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
3232
with:
3333
fetch-depth: 0 # Fetches the entire history
3434

@@ -106,7 +106,7 @@ jobs:
106106
if: ${{ always() }}
107107
name: Run E2E tests in AWS device farm
108108
steps:
109-
- uses: actions/checkout@v4
109+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
110110
with:
111111
# The OS_BOTIFY_COMMIT_TOKEN is a personal access token tied to osbotify (we need a PAT to access the artifact API)
112112
token: ${{ secrets.OS_BOTIFY_COMMIT_TOKEN }}
@@ -315,7 +315,7 @@ jobs:
315315
if: ${{ always() && needs.prep.outputs.IS_PR_MERGED != 'true' }}
316316
runs-on: ubuntu-latest
317317
steps:
318-
- uses: actions/checkout@v4
318+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
319319

320320
- name: Delete temporary merge branch created for delta ref
321321
run: git push -d origin ${{ needs.prep.outputs.DELTA_REF }}

.github/workflows/preDeploy.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
if: ${{ always() }}
2626

2727
steps:
28-
- uses: actions/checkout@v4
28+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
2929

3030
- name: Announce failed workflow in Slack
3131
if: ${{ needs.typecheck.result == 'failure' || needs.lint.result == 'failure' || needs.test.result == 'failure' }}
@@ -47,7 +47,7 @@ jobs:
4747
SHOULD_DEPLOY: ${{ fromJSON(steps.shouldDeploy.outputs.SHOULD_DEPLOY) }}
4848

4949
steps:
50-
- uses: actions/checkout@v4
50+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
5151

5252
- name: Get merged pull request
5353
id: getMergedPullRequest

.github/workflows/proposalPolice.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
if: "!contains(fromJSON('[\"OSBotify\", \"imgbot[bot]\", \"melvin-bot[bot]\"]'), github.actor)"
1010
steps:
11-
- uses: actions/checkout@v4
11+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
1212

1313
# Checks if the comment is created and follows the template OR
1414
# if the comment is edited and if proposal template is followed.

.github/workflows/remote-build-android.yml

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ name: Remote Build Android
22

33
on:
44
workflow_dispatch:
5+
push:
6+
branches-ignore: [staging, production]
57

68
concurrency:
79
group: ${{ github.workflow }}-${{ github.ref }}

.github/workflows/reviewerChecklist.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]'
1111
steps:
12-
- uses: actions/checkout@v4
12+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
1313

1414
- name: reviewerChecklist.js
1515
uses: ./.github/actions/javascript/reviewerChecklist

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
runs-on: ubuntu-latest
5151
name: Storybook tests
5252
steps:
53-
- uses: actions/checkout@v4
53+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
5454

5555
- uses: ./.github/actions/composite/setupNode
5656

.github/workflows/typecheck.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/checkout@v4
19+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
2020

2121
- uses: ./.github/actions/composite/setupNode
2222
with:

.github/workflows/validateDocsRoutes.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]'
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v4
14+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
1515

1616
- uses: ./.github/actions/composite/setupNode
1717

.github/workflows/verifySignedCommits.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
verifySignedCommits:
1010
runs-on: ubuntu-latest
1111
steps:
12-
- uses: actions/checkout@v4
12+
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
1313

1414
- name: Verify signed commits
1515
uses: ./.github/actions/javascript/verifySignedCommits

Mobile-Expensify

android/app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ android {
114114
minSdkVersion rootProject.ext.minSdkVersion
115115
targetSdkVersion rootProject.ext.targetSdkVersion
116116
multiDexEnabled rootProject.ext.multiDexEnabled
117-
versionCode 1009014001
118-
versionName "9.1.40-1"
117+
versionCode 1009014200
118+
versionName "9.1.42-0"
119119
// Supported language variants must be declared here to avoid from being removed during the compilation.
120120
// This also helps us to not include unnecessary language variants in the APK.
121121
resConfigs "en", "es"

docs/articles/expensify-classic/bank-accounts-and-payments/payments/Global-Reimbursement-UK.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ If your business operates out of the U.K., you can enable global reimbursements
5454
This is a signed document authorizing a client’s bank to pull payments via direct debit.
5555

5656
1. Expensify will send you a **Direct Debit Authorization** form to sign.
57-
3. Send the signed authorization form to your bank.
58-
4. Return the signed authorization form to Expensify.
59-
5. Once the account is set up for direct debits (typically takes 10 to 12 business days to complete), communicate to Expensify support that is complete.
57+
2. Send the signed authorization form to your bank.
58+
3. Return the signed authorization form to Expensify.
59+
4. Once the account is set up for direct debits (typically takes 10 to 12 business days to complete), communicate to Expensify support that is complete.
6060

6161
---
6262

Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
---
22
title: Set Time and Distance Rates
3-
description: Set rates for hourly and Distance expenses
4-
keywords: [Expensify Classic, distance rates, time rates]
3+
description: Configure default hourly and mileage reimbursement rates at the workspace level for consistent billing and expense tracking.
4+
keywords: [Expensify Classic, distance rates, mileage rates, time tracking, hourly rates, workspace settings]
55
---
66
<div id="expensify-classic" markdown="1">
77

8-
You can set default rates at the workspace level to track employees' billable time and mileage expenses. Configuring these settings will ensure consistent reimbursement calculations and accurate billing for your team.
8+
Set default rates at the workspace level to track billable time and mileage expenses. This ensures accurate and consistent reimbursement for your team.
99

1010
---
1111

12-
# Set Time and Distance Rates
13-
14-
Head to **Settings > Workspace > [Workspace Name] > Distance rates:**
15-
- **For distance:**
16-
- If desired, adjust your **unit** (miles or kilometers) and your **default category**. These options will apply to all of your distance rates.
17-
- To add a new rate, click **Add a Mileage Rate**.
18-
- To edit an existing rate:
19-
- Click the toggle to enable or disable the rate.
20-
- Click the **name** or **rate** field to make changes.
21-
- **For time:**
22-
- Click the **enable** toggle to enable hourly rate expenses.
23-
- Enter the **default hourly rate**.
12+
# Distance Rates
13+
14+
To configure mileage reimbursement:
15+
16+
1. Go to **Settings > Workspaces > [Workspace Name] > Distance rates**
17+
2. Adjust your **unit** (miles or kilometers) and your **default category**—these apply to all distance rates.
18+
3. Click **Add a Mileage Rate** to create a new rate.
19+
20+
## Edit an Existing Rate
21+
1. Toggle the switch to enable or disable the rate.
22+
2. Click the **name** or **rate** field to make changes.
23+
24+
---
25+
26+
# Time Expenses
27+
28+
To enable hourly rate reimbursement:
29+
30+
1. Go to **Settings > Workspaces > [Workspace Name] > Distance rates**
31+
2. Toggle **Enable hourly rate expenses**
32+
3. Enter the **default hourly rate**
2433

2534
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
title: Prohibited Expenses Rule
3+
description: Learn how to enable and use the Prohibited expenses rule to automatically flag receipts with restricted items such as alcohol, gambling, or tobacco.
4+
keywords: [prohibited expenses, receipt violation, SmartScan, alcohol, gambling, expense rules, workspace settings, line item compliance]
5+
---
6+
<div id="new-expensify" markdown="1">
7+
8+
Enable the **Prohibited expenses** rule to automatically flag receipts containing restricted purchases like alcohol, gambling, or tobacco. This rule uses Expensify’s AI-powered SmartScan to detect violations at the line-item level and notify admins for review.
9+
10+
# Prohibited Expense Rule
11+
12+
The Prohibited expenses rule allows Workspace Admins to enforce compliance by flagging receipts that contain restricted items. SmartScan analyzes individual line items and applies violations when prohibited categories are detected.
13+
14+
## How it works
15+
16+
Once enabled, this rule uses AI to review receipt line items during SmartScan. If a prohibited item is found, the expense is flagged for review.
17+
18+
- Available in both Expensify Classic and New Expensify.
19+
- Configuration is only available in New Expensify.
20+
- Automatically flags receipts for manual review by a Workspace Admin or approver.
21+
22+
## How to enable the rule
23+
24+
To turn on the Prohibited expenses rule:
25+
26+
1. Go to **Settings** > **Workspaces** > click _Workspace Name_ > **Rules** > **Expenses**.
27+
2. Scroll to the section titled **Prohibited expenses**.
28+
3. Toggle on the rule.
29+
4. Select the prohibited categories you want to monitor:
30+
- Adult entertainment
31+
- Alcohol
32+
- Gambling
33+
- Hotel incidentals
34+
- Tobacco
35+
36+
**Note:** This rule is disabled by default. Admins must enable it and choose which categories to apply.
37+
38+
## What happens when a prohibited item is detected?
39+
40+
If a SmartScan detects a prohibited item:
41+
42+
- A violation is added to the expense.
43+
- The expense displays the messages:
44+
- `"Receipt Issue Found"`
45+
- `"Prohibited expense: Alcohol"` (or the relevant flagged category).
46+
- The expense requires manual review by the approver.
47+
48+
---
49+
50+
# FAQ
51+
52+
## Who can enable the Prohibited Expenses Rule?
53+
54+
Only Workspace Admins can enable or adjust this rule in New Expensify.
55+
56+
## Will violations appear in Expensify Classic?
57+
58+
Yes. Even though configuration is handled in New Expensify, violations appear in both **Expensify Classic** and **New Expensify** when viewing expenses.
59+
60+
If the Domain Group setting, **Strictly enforce expense workspace rules** is enabled, it will block the submission of the expense with the prohibited item violation.
61+
62+
## Will SmartScan still work if the rule is off?
63+
64+
Yes. SmartScan will still extract the merchant, date, and amount. However, it will not flag line items for violations unless the rule is enabled.
65+
66+
## Is this rule part of SmartScan?
67+
68+
Yes. Once enabled, the rule works seamlessly with SmartScan to detect prohibited line items in all scanned receipts.
69+
70+
</div>

docs/articles/new-expensify/workspaces/Set-up-rules.md

+16
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ Once Rules are enabled, you can customize individual expense settings:
3030
- **Billable default**: Set expenses as billable or non-billable by default.
3131
- **eReceipts**: Enable eReceipts for most USD credit transactions. This is available when the Default currency set in the Overview is set to USD.
3232

33+
# Configure Prohibited Expense Rule
34+
35+
To flag restricted expense types for manual review:
36+
37+
1. Go to **Settings** > **Workspaces** > click **Workspace Name** > **Rules** > **Expenses**.
38+
2. Scroll to the **Prohibited expenses** section.
39+
3. Toggle on the feature, then select the types of restricted items to flag:
40+
- Alcohol
41+
- Gambling
42+
- Tobacco
43+
- Hotel incidentals
44+
- Adult entertainment
45+
4. If an uploaded receipt contains any of the flagged items, the expense will be marked for manual review.
46+
47+
**Note:** Prohibited expense violations appear in both New Expensify and Expensify Classic. However, a Workspace Admin must enable the rules in **New Expensify** for them to take effect.
48+
3349
# Configure expense report rules
3450

3551
1. Click **Rules** in the left menu.

0 commit comments

Comments
 (0)