Skip to content

Commit

Permalink
Merge branch 'main' into fix/34120
Browse files Browse the repository at this point in the history
  • Loading branch information
dukenv0307 committed Apr 22, 2024
2 parents 67a43d7 + 995f914 commit 7a748f5
Show file tree
Hide file tree
Showing 287 changed files with 7,586 additions and 4,815 deletions.
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ module.exports = {
rules: {
'prefer-regex-literals': 'off',
'rulesdir/no-multiple-onyx-in-file': 'off',
'rulesdir/onyx-props-must-have-default': 'off',
'react-native-a11y/has-accessibility-hint': ['off'],
'react/jsx-no-constructed-context-values': 'error',
'react-native-a11y/has-valid-accessibility-descriptors': [
Expand Down
64 changes: 64 additions & 0 deletions .github/scripts/detectRedirectCycle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {parse} from 'csv-parse';
import fs from 'fs';

const parser = parse();

const adjacencyList: Record<string, string[]> = {};
const visited: Map<string, boolean> = new Map<string, boolean>();
const backEdges: Map<string, boolean> = new Map<string, boolean>();

function addEdge(source: string, target: string) {
if (!adjacencyList[source]) {
adjacencyList[source] = [];
}
adjacencyList[source].push(target);
}

function isCyclic(currentNode: string): boolean {
visited.set(currentNode, true);
backEdges.set(currentNode, true);

// Do a depth first search for all the neighbours. If a node is found in backedge, a cycle is detected.
const neighbours = adjacencyList[currentNode];
if (neighbours) {
for (const node of neighbours) {
if (!visited.has(node)) {
if (isCyclic(node)) {
return true;
}
} else if (backEdges.has(node)) {
return true;
}
}
}

backEdges.delete(currentNode);

return false;
}

function detectCycle(): boolean {
for (const [node] of Object.entries(adjacencyList)) {
if (!visited.has(node)) {
if (isCyclic(node)) {
const cycle = Array.from(backEdges.keys());
console.log(`Infinite redirect found in the cycle: ${cycle.join(' -> ')} -> ${node}`);
return true;
}
}
}
return false;
}

fs.createReadStream(`${process.cwd()}/docs/redirects.csv`)
.pipe(parser)
.on('data', (row) => {
// Create a directed graph of sourceURL -> targetURL
addEdge(row[0], row[1]);
})
.on('end', () => {
if (detectCycle()) {
process.exit(1);
}
process.exit(0);
});
26 changes: 26 additions & 0 deletions .github/scripts/verifyRedirect.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

# HelpDot - Verifies that redirects.csv does not have any duplicates
# Duplicate sourceURLs break redirection on cloudflare pages

declare -r REDIRECTS_FILE="docs/redirects.csv"

declare -r RED='\033[0;31m'
declare -r GREEN='\033[0;32m'
declare -r NC='\033[0m'

duplicates=$(awk -F, 'a[$1]++{print $1}' $REDIRECTS_FILE)
if [[ -n "$duplicates" ]]; then
echo "${RED}duplicate redirects are not allowed: $duplicates ${NC}"
exit 1
fi

npm run detectRedirectCycle
DETECT_CYCLE_EXIT_CODE=$?
if [[ DETECT_CYCLE_EXIT_CODE -eq 1 ]]; then
echo -e "${RED}The redirects.csv has a cycle. Please remove the redirect cycle because it will cause an infinite redirect loop ${NC}"
exit 1
fi

echo -e "${GREEN}The redirects.csv is valid!${NC}"
exit 0
3 changes: 3 additions & 0 deletions .github/workflows/deployExpensifyHelp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ jobs:
- name: Create docs routes file
run: ./.github/scripts/createDocsRoutes.sh

- name: Check for duplicates and cycles in redirects.csv
run: ./.github/scripts/verifyRedirect.sh

- name: Build with Jekyll
uses: actions/jekyll-build-pages@0143c158f4fa0c5dcd99499a5d00859d79f70b0e
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/e2ePerformanceTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:
if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }}
id: getMergeCommitShaIfUnmergedPR
run: |
git merge --allow-unrelated-histories --no-commit ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }}
git merge --allow-unrelated-histories -X ours --no-commit ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }}
git checkout ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }}
env:
GITHUB_TOKEN: ${{ github.token }}
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/platformDeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ jobs:
MYAPP_UPLOAD_STORE_PASSWORD: ${{ secrets.MYAPP_UPLOAD_STORE_PASSWORD }}
MYAPP_UPLOAD_KEY_PASSWORD: ${{ secrets.MYAPP_UPLOAD_KEY_PASSWORD }}

- name: Run Fastlane production
if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }}
run: bundle exec fastlane android production
env:
VERSION: ${{ env.VERSION_CODE }}
# Note: Android production deploys are temporarily disabled until https://github.com/Expensify/App/issues/40108 is resolved
# - name: Run Fastlane production
# if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }}
# run: bundle exec fastlane android production
# env:
# VERSION: ${{ env.VERSION_CODE }}

- name: Archive Android sourcemaps
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -158,7 +159,7 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
GCP_GEOLOCATION_API_KEY: $${{ secrets.GCP_GEOLOCATION_API_KEY_PRODUCTION }}


- name: Build staging desktop app
if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }}
Expand Down
10 changes: 3 additions & 7 deletions .well-known/apple-app-site-association
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@
"/": "/iou/*",
"comment": "I Owe You reports"
},
{
"/": "/request/*",
"comment": "Money request"
},
{
"/": "/enable-payments/*",
"comment": "Payments setup"
Expand All @@ -54,11 +50,11 @@
},
{
"/": "/split/*",
"comment": "Split Bill"
"comment": "Split Expense"
},
{
"/": "/request/*",
"comment": "Request Money"
"comment": "Submit Expense"
},
{
"/": "/new/*",
Expand All @@ -82,7 +78,7 @@
},
{
"/": "/send/*",
"comment": "Send money"
"comment": "Pay someone"
},
{
"/": "/money2020/*",
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ If you want to run the app on an actual physical iOS device, please follow the i
## Running the MacOS desktop app 🖥
* To run the **Development app**, run: `npm run desktop`, this will start a new Electron process running on your MacOS desktop in the `dist/Mac` folder.

## Receiving Notifications
To receive notifications on development build of the app while hitting the Staging or Production API, you need to use the production airship config.
### Android
1. Copy the [production config](https://github.com/Expensify/App/blob/d7c1256f952c0020344d809ee7299b49a4c70db2/android/app/src/main/assets/airshipconfig.properties#L1-L7) to the [development config](https://github.com/Expensify/App/blob/d7c1256f952c0020344d809ee7299b49a4c70db2/android/app/src/development/assets/airshipconfig.properties#L1-L8).
2. Rebuild the app.

### iOS
1. Replace the [development key and secret](https://github.com/Expensify/App/blob/d7c1256f952c0020344d809ee7299b49a4c70db2/ios/AirshipConfig.plist#L7-L10) with the [production values](https://github.com/Expensify/App/blob/d7c1256f952c0020344d809ee7299b49a4c70db2/ios/AirshipConfig.plist#L11-L14).
2. Rebuild the app.

## Troubleshooting
1. If you are having issues with **_Getting Started_**, please reference [React Native's Documentation](https://reactnative.dev/docs/environment-setup)
2. If you are running into CORS errors like (in the browser dev console)
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001046213
versionName "1.4.62-13"
versionCode 1001046316
versionName "1.4.63-16"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: Enable and set up expense violations
description: Set up rules for expenses and enable violations
---
<div id="expensify-classic" markdown="1">

Expensify automatically detects expense errors or discrepancies as violations that must be corrected. You can also set rules for a workspace that will trigger a violation if the rule is not met. These rules can be set for categories, tags, and even for specific domain groups.

When reviewing submitted expense reports, approvers will see violations highlighted with an exclamation mark. There are two types of violations:
- **Yellow**: Automated highlights that require attention but may not require corrective action. For example, if a receipt was SmartScanned and then the amount was modified, a yellow violation will be added to call out the change for review.
- **Red**: Violations directly tied to your workspace settings. These violations must be addressed before the report can be submitted and reimbursed.

You can hover over the icon to see a brief description, and you can find more detailed information below the list of expenses.

{% include info.html %}
If your workspace has automations set to automatically submit reports for approval, the report that contains violations will not be submitted automatically until the violations are corrected. (However, if a comment is added to an expense, it will override the violation as the member is providing a reason for submission *unless* domain workspace rules are set to be strictly enforced, as detailed near the bottom of this article.)
{% include end-info.html %}

# Enable or disable expense violations

1. Hover over Settings, then click **Workspaces**.
2. Click the **Group** tab on the left.
3. Click the desired workspace name.
4. Click the **Expenses** tab on the left.
5. Click the “Enable violations” toggle.
6. If desired, enter the expense rules that will be used to create violations:
- **Max expense age (days)**: How old an expense can be
- **Max expense amount**: How much a single expense can cost
- **Receipt required amount**: How much a single expense can cost before a receipt is required

{% include info.html %}
Expensify includes certain system mandatory violations that can't be disabled, even if your policy has violations turned off.
{% include end-info.html %}

# Set category rules

Admins on a Control workspace can enable specific rules for each category, including setting expense caps for specific categories, requiring receipts, and more. These rules can allow you to have a default expense limit of $2,500 but to only allow a daily entertainment limit of $150 per person. You can also choose to not require receipts for mileage or per diem expenses.

To set up category rules,
1. Hover over Settings, then click **Workspaces**.
2. Click the **Group** tab on the left.
3. Click the desired workspace name.
4. Click the **Categories** tab on the left.
5. Click **Edit** to the right of the category.
6. Enter your category rules, as desired:
- **GL Code and Payroll Code**: You can add general ledger (GL) or payroll codes to the category for accounting. GL codes populate automatically if you have an accounting integration connected with Expensify.
- **Max Amount**: You can set specific expense caps for the expense category. Use the Limit Type dropdown to determine if the amount is set per individual expense or per day, then enter the maximum amount into this field.
- **Receipts**: You can determine whether receipts are required for the category. For example, many companies disable receipt requirements for toll expenses.
- **Description**: You can determine whether a description is required for expenses under this category.
- **Description Hint**: You can add a hint in the description field to prompt the expense creator on what they should enter into the description field for expenses under this category.
- **Approver**: You can set a specific approver for expenses labeled with this category.

If users are in violation of these rules, the violations will be shown in red on the report.

{% include info.html %}
If Scheduled Submit is enabled on a workspace, expenses with category violations will not be auto-submitted unless the expense has a comment added.
{% include end-info.html %}

# Make categories required

This means all expenses must be coded with a Category.

1. Hover over Settings, then click **Workspaces**.
2. Click the **Group** tab on the left.
3. Click the desired workspace name.
4. Click the **Categories** tab on the left.
5. Enable the “People must categorize expenses” toggle.

Each Workspace Member will now be required to select a category for their expense. If they do not select a category, the report will receive a violation, which can prevent submission if Scheduled Submit is enabled.

# Make tags required

1. Hover over Settings, then click **Workspaces**.
2. Click the **Group** tab on the left.
3. Click the desired workspace name.
4. Click the **Tags** tab on the left.
5. Enable the “People must tag expenses” toggle.

Each Workspace Member will now be required to select a tag for their expense before they’re able to submit it.

# Require strict compliance by domain group

You can require strict compliance to require members of a specific domain group to submit reports that meet **all** workspace rules before they can submit their expense report—even if they add a note. Every rule and regulation on the workspace must be met before a report can be submitted.

{% include info.html %}
This will prevent members from submitting any reports where a manager has granted them a manual exception for any of the workspace rules.
{% include end-info.html %}

To enable strict domain group compliance for reports,

1. Hover over Settings, then click **Domains**.
2. Click the **Groups** tab on the left.
3. Click **Edit** to the right of the desired workspace name.
4. Enable the “Strictly enforce expense workspace rules” toggle.

# FAQs

**Why can’t my employees see the categories on their expenses?**

The employee may have their default workspace set as their personal workspace. Look under the details section on top right of the report to ensure it is being reported under the correct workspace.

**Will the account numbers from our accounting system (QuickBooks Online, Sage Intacct, etc.) show in the category list for employees?**

The general ledger (GL) account numbers are visible only for Workspace Admins in the workspace settings when they are part of a control workspace. This information is not visible to other members of the workspace. However, if you wish to have this information available to your employees when they are categorizing their expenses, you can edit the account name in your accounting software to include the GL number (for example, Accounts Payable - 12345).

**What causes a category violation?**

- An expense is categorized with a category that is not included in the workspace's categories. This may happen if the employee creates an expense under the wrong workspace, which will cause a "category out of workspace" violation.
- If the workspace categories are being imported from an accounting integration and they’ve been updated in the accounting system but not in Expensify, this can cause an old category to still be in use on an open report which would throw a violation on submission. Simply reselect a proper category to clear violation.

</div>
Loading

0 comments on commit 7a748f5

Please sign in to comment.