diff --git a/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts b/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts index b9d01702e66e..da946b78a056 100644 --- a/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts +++ b/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts @@ -1,13 +1,83 @@ import * as core from '@actions/core'; import * as github from '@actions/github'; +import type {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods/dist-types/generated/parameters-and-response-types'; import {getJSONInput} from '@github/libs/ActionUtils'; import GithubUtils from '@github/libs/GithubUtils'; import GitUtils from '@github/libs/GitUtils'; +type WorkflowRun = RestEndpointMethodTypes['actions']['listWorkflowRuns']['response']['data']['workflow_runs'][number]; + +const BUILD_AND_DEPLOY_JOB_NAME_PREFIX = 'Build and deploy'; + +/** + * This function checks if a given release is a valid baseTag to get the PR list with `git log baseTag...endTag`. + * + * The rules are: + * - production deploys can only be compared with other production deploys + * - staging deploys can be compared with other staging deploys or production deploys. + * The reason is that the final staging release in each deploy cycle will BECOME a production release. + * For example, imagine a checklist is closed with version 9.0.20-6; that's the most recent staging deploy, but the release for 9.0.20-6 is now finalized, so it looks like a prod deploy. + * When 9.0.21-0 finishes deploying to staging, the most recent prerelease is 9.0.20-5. However, we want 9.0.20-6...9.0.21-0, + * NOT 9.0.20-5...9.0.21-0 (so that the PR CP'd in 9.0.20-6 is not included in the next checklist) + */ +async function isReleaseValidBaseForEnvironment(releaseTag: string, isProductionDeploy: boolean) { + if (!isProductionDeploy) { + return true; + } + const isPrerelease = ( + await GithubUtils.octokit.repos.getReleaseByTag({ + owner: github.context.repo.owner, + repo: github.context.repo.repo, + tag: releaseTag, + }) + ).data.prerelease; + return !isPrerelease; +} + +/** + * Was a given platformDeploy workflow run successful on at least one platform? + */ +async function wasDeploySuccessful(runID: number) { + const jobsForWorkflowRun = ( + await GithubUtils.octokit.actions.listJobsForWorkflowRun({ + owner: github.context.repo.owner, + repo: github.context.repo.repo, + // eslint-disable-next-line @typescript-eslint/naming-convention + run_id: runID, + filter: 'latest', + }) + ).data.jobs; + return jobsForWorkflowRun.some((job) => job.name.startsWith(BUILD_AND_DEPLOY_JOB_NAME_PREFIX) && job.conclusion === 'success'); +} + +/** + * This function checks if a given deploy workflow is a valid basis for comparison when listing PRs merged between two versions. + * It returns the reason a version should be skipped, or an empty string if the version should not be skipped. + */ +async function shouldSkipVersion(lastSuccessfulDeploy: WorkflowRun, inputTag: string, isProductionDeploy: boolean): Promise { + if (!lastSuccessfulDeploy?.head_branch) { + // This should never happen. Just doing this to appease TS. + return ''; + } + + // we never want to compare a tag with itself. This check is necessary because prod deploys almost always have the same version as the last staging deploy. + // In this case, the next for wrong environment fails because the release that triggered that staging deploy is now finalized, so it looks like a prod deploy. + if (lastSuccessfulDeploy?.head_branch === inputTag) { + return `Same as input tag ${inputTag}`; + } + if (!(await isReleaseValidBaseForEnvironment(lastSuccessfulDeploy?.head_branch, isProductionDeploy))) { + return 'Was a staging deploy, we only want to compare with other production deploys'; + } + if (!(await wasDeploySuccessful(lastSuccessfulDeploy.id))) { + return 'Was an unsuccessful deploy, nothing was deployed in that version'; + } + return ''; +} + async function run() { try { const inputTag = core.getInput('TAG', {required: true}); - const isProductionDeploy = getJSONInput('IS_PRODUCTION_DEPLOY', {required: false}, false); + const isProductionDeploy = !!getJSONInput('IS_PRODUCTION_DEPLOY', {required: false}, false); const deployEnv = isProductionDeploy ? 'production' : 'staging'; console.log(`Looking for PRs deployed to ${deployEnv} in ${inputTag}...`); @@ -27,33 +97,26 @@ async function run() { // Find the most recent deploy workflow targeting the correct environment, for which at least one of the build jobs finished successfully let lastSuccessfulDeploy = completedDeploys.shift(); - while ( - lastSuccessfulDeploy?.head_branch && - (( - await GithubUtils.octokit.repos.getReleaseByTag({ - owner: github.context.repo.owner, - repo: github.context.repo.repo, - tag: lastSuccessfulDeploy.head_branch, - }) - ).data.prerelease === isProductionDeploy || - !( - await GithubUtils.octokit.actions.listJobsForWorkflowRun({ - owner: github.context.repo.owner, - repo: github.context.repo.repo, - // eslint-disable-next-line @typescript-eslint/naming-convention - run_id: lastSuccessfulDeploy.id, - filter: 'latest', - }) - ).data.jobs.some((job) => job.name.startsWith('Build and deploy') && job.conclusion === 'success')) - ) { - console.log(`Deploy was not a success: ${lastSuccessfulDeploy.html_url}, looking at the next one`); - lastSuccessfulDeploy = completedDeploys.shift(); - } if (!lastSuccessfulDeploy) { throw new Error('Could not find a prior successful deploy'); } + let reason = await shouldSkipVersion(lastSuccessfulDeploy, inputTag, isProductionDeploy); + while (lastSuccessfulDeploy && reason) { + console.log( + `Deploy of tag ${lastSuccessfulDeploy.head_branch} was not valid as a base for comparison, looking at the next one. Reason: ${reason}`, + lastSuccessfulDeploy.html_url, + ); + lastSuccessfulDeploy = completedDeploys.shift(); + + if (!lastSuccessfulDeploy) { + throw new Error('Could not find a prior successful deploy'); + } + + reason = await shouldSkipVersion(lastSuccessfulDeploy, inputTag, isProductionDeploy); + } + const priorTag = lastSuccessfulDeploy.head_branch; console.log(`Looking for PRs deployed to ${deployEnv} between ${priorTag} and ${inputTag}`); const prList = await GitUtils.getPullRequestsMergedBetween(priorTag ?? '', inputTag); diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index 05ae086fcc24..e8bd7057d40e 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -11502,10 +11502,68 @@ const github = __importStar(__nccwpck_require__(5438)); const ActionUtils_1 = __nccwpck_require__(6981); const GithubUtils_1 = __importDefault(__nccwpck_require__(9296)); const GitUtils_1 = __importDefault(__nccwpck_require__(1547)); +const BUILD_AND_DEPLOY_JOB_NAME_PREFIX = 'Build and deploy'; +/** + * This function checks if a given release is a valid baseTag to get the PR list with `git log baseTag...endTag`. + * + * The rules are: + * - production deploys can only be compared with other production deploys + * - staging deploys can be compared with other staging deploys or production deploys. + * The reason is that the final staging release in each deploy cycle will BECOME a production release. + * For example, imagine a checklist is closed with version 9.0.20-6; that's the most recent staging deploy, but the release for 9.0.20-6 is now finalized, so it looks like a prod deploy. + * When 9.0.21-0 finishes deploying to staging, the most recent prerelease is 9.0.20-5. However, we want 9.0.20-6...9.0.21-0, + * NOT 9.0.20-5...9.0.21-0 (so that the PR CP'd in 9.0.20-6 is not included in the next checklist) + */ +async function isReleaseValidBaseForEnvironment(releaseTag, isProductionDeploy) { + if (!isProductionDeploy) { + return true; + } + const isPrerelease = (await GithubUtils_1.default.octokit.repos.getReleaseByTag({ + owner: github.context.repo.owner, + repo: github.context.repo.repo, + tag: releaseTag, + })).data.prerelease; + return !isPrerelease; +} +/** + * Was a given platformDeploy workflow run successful on at least one platform? + */ +async function wasDeploySuccessful(runID) { + const jobsForWorkflowRun = (await GithubUtils_1.default.octokit.actions.listJobsForWorkflowRun({ + owner: github.context.repo.owner, + repo: github.context.repo.repo, + // eslint-disable-next-line @typescript-eslint/naming-convention + run_id: runID, + filter: 'latest', + })).data.jobs; + return jobsForWorkflowRun.some((job) => job.name.startsWith(BUILD_AND_DEPLOY_JOB_NAME_PREFIX) && job.conclusion === 'success'); +} +/** + * This function checks if a given deploy workflow is a valid basis for comparison when listing PRs merged between two versions. + * It returns the reason a version should be skipped, or an empty string if the version should not be skipped. + */ +async function shouldSkipVersion(lastSuccessfulDeploy, inputTag, isProductionDeploy) { + if (!lastSuccessfulDeploy?.head_branch) { + // This should never happen. Just doing this to appease TS. + return ''; + } + // we never want to compare a tag with itself. This check is necessary because prod deploys almost always have the same version as the last staging deploy. + // In this case, the next for wrong environment fails because the release that triggered that staging deploy is now finalized, so it looks like a prod deploy. + if (lastSuccessfulDeploy?.head_branch === inputTag) { + return `Same as input tag ${inputTag}`; + } + if (!(await isReleaseValidBaseForEnvironment(lastSuccessfulDeploy?.head_branch, isProductionDeploy))) { + return 'Was a staging deploy, we only want to compare with other production deploys'; + } + if (!(await wasDeploySuccessful(lastSuccessfulDeploy.id))) { + return 'Was an unsuccessful deploy, nothing was deployed in that version'; + } + return ''; +} async function run() { try { const inputTag = core.getInput('TAG', { required: true }); - const isProductionDeploy = (0, ActionUtils_1.getJSONInput)('IS_PRODUCTION_DEPLOY', { required: false }, false); + const isProductionDeploy = !!(0, ActionUtils_1.getJSONInput)('IS_PRODUCTION_DEPLOY', { required: false }, false); const deployEnv = isProductionDeploy ? 'production' : 'staging'; console.log(`Looking for PRs deployed to ${deployEnv} in ${inputTag}...`); const completedDeploys = (await GithubUtils_1.default.octokit.actions.listWorkflowRuns({ @@ -11520,25 +11578,18 @@ async function run() { .filter((workflowRun) => workflowRun.conclusion !== 'cancelled'); // Find the most recent deploy workflow targeting the correct environment, for which at least one of the build jobs finished successfully let lastSuccessfulDeploy = completedDeploys.shift(); - while (lastSuccessfulDeploy?.head_branch && - ((await GithubUtils_1.default.octokit.repos.getReleaseByTag({ - owner: github.context.repo.owner, - repo: github.context.repo.repo, - tag: lastSuccessfulDeploy.head_branch, - })).data.prerelease === isProductionDeploy || - !(await GithubUtils_1.default.octokit.actions.listJobsForWorkflowRun({ - owner: github.context.repo.owner, - repo: github.context.repo.repo, - // eslint-disable-next-line @typescript-eslint/naming-convention - run_id: lastSuccessfulDeploy.id, - filter: 'latest', - })).data.jobs.some((job) => job.name.startsWith('Build and deploy') && job.conclusion === 'success'))) { - console.log(`Deploy was not a success: ${lastSuccessfulDeploy.html_url}, looking at the next one`); - lastSuccessfulDeploy = completedDeploys.shift(); - } if (!lastSuccessfulDeploy) { throw new Error('Could not find a prior successful deploy'); } + let reason = await shouldSkipVersion(lastSuccessfulDeploy, inputTag, isProductionDeploy); + while (lastSuccessfulDeploy && reason) { + console.log(`Deploy of tag ${lastSuccessfulDeploy.head_branch} was not valid as a base for comparison, looking at the next one. Reason: ${reason}`, lastSuccessfulDeploy.html_url); + lastSuccessfulDeploy = completedDeploys.shift(); + if (!lastSuccessfulDeploy) { + throw new Error('Could not find a prior successful deploy'); + } + reason = await shouldSkipVersion(lastSuccessfulDeploy, inputTag, isProductionDeploy); + } const priorTag = lastSuccessfulDeploy.head_branch; console.log(`Looking for PRs deployed to ${deployEnv} between ${priorTag} and ${inputTag}`); const prList = await GitUtils_1.default.getPullRequestsMergedBetween(priorTag ?? '', inputTag); diff --git a/.github/actions/javascript/proposalPoliceComment/index.js b/.github/actions/javascript/proposalPoliceComment/index.js index c14b825e1198..9b5b56f11a11 100644 --- a/.github/actions/javascript/proposalPoliceComment/index.js +++ b/.github/actions/javascript/proposalPoliceComment/index.js @@ -17987,6 +17987,8 @@ function isCommentCreatedEvent(payload) { } // Main function to process the workflow event async function run() { + // get date early, as soon as the workflow starts running + const date = new Date(); // Verify this is running for an expected webhook event if (github_1.context.eventName !== CONST_1.default.EVENTS.ISSUE_COMMENT) { throw new Error('ProposalPolice™ only supports the issue_comment webhook event'); @@ -18046,8 +18048,7 @@ async function run() { // extract the text after [EDIT_COMMENT] from assistantResponse since this is a // bot related action keyword let extractedNotice = assistantResponse.split('[EDIT_COMMENT] ')?.[1]?.replace('"', ''); - // format the github's updated_at like: 2024-01-24 13:15:24 UTC not 2024-01-28 18:18:28.000 UTC - const date = new Date(payload.comment?.updated_at ?? ''); + // format the date like: 2024-01-24 13:15:24 UTC not 2024-01-28 18:18:28.000 UTC const formattedDate = `${date.toISOString()?.split('.')?.[0]?.replace('T', ' ')} UTC`; extractedNotice = extractedNotice.replace('{updated_timestamp}', formattedDate); console.log('ProposalPolice™ editing issue comment...', payload.comment.id); diff --git a/.github/actions/javascript/proposalPoliceComment/proposalPoliceComment.ts b/.github/actions/javascript/proposalPoliceComment/proposalPoliceComment.ts index fa18ae833768..19d3037a80a5 100644 --- a/.github/actions/javascript/proposalPoliceComment/proposalPoliceComment.ts +++ b/.github/actions/javascript/proposalPoliceComment/proposalPoliceComment.ts @@ -15,6 +15,8 @@ function isCommentCreatedEvent(payload: IssueCommentEvent): payload is IssueComm // Main function to process the workflow event async function run() { + // get date early, as soon as the workflow starts running + const date = new Date(); // Verify this is running for an expected webhook event if (context.eventName !== CONST.EVENTS.ISSUE_COMMENT) { throw new Error('ProposalPolice™ only supports the issue_comment webhook event'); @@ -87,8 +89,7 @@ async function run() { // extract the text after [EDIT_COMMENT] from assistantResponse since this is a // bot related action keyword let extractedNotice = assistantResponse.split('[EDIT_COMMENT] ')?.[1]?.replace('"', ''); - // format the github's updated_at like: 2024-01-24 13:15:24 UTC not 2024-01-28 18:18:28.000 UTC - const date = new Date(payload.comment?.updated_at ?? ''); + // format the date like: 2024-01-24 13:15:24 UTC not 2024-01-28 18:18:28.000 UTC const formattedDate = `${date.toISOString()?.split('.')?.[0]?.replace('T', ' ')} UTC`; extractedNotice = extractedNotice.replace('{updated_timestamp}', formattedDate); console.log('ProposalPolice™ editing issue comment...', payload.comment.id); diff --git a/.github/scripts/createHelpRedirects.sh b/.github/scripts/createHelpRedirects.sh index 14ed9de953fc..1425939ff3ec 100755 --- a/.github/scripts/createHelpRedirects.sh +++ b/.github/scripts/createHelpRedirects.sh @@ -27,32 +27,6 @@ function checkCloudflareResult { declare -a ITEMS_TO_ADD while read -r line; do - # Split each line of the file into a source and destination so we can sanity check - # and compare against the current list. - read -r -a LINE_PARTS < <(echo "$line" | tr ',' ' ') - SOURCE_URL=${LINE_PARTS[0]} - DEST_URL=${LINE_PARTS[1]} - - # Make sure the format of the line is as execpted. - if [[ "${#LINE_PARTS[@]}" -gt 2 ]]; then - error "Found a line with more than one comma: $line" - exit 1 - fi - - # Basic sanity checking to make sure that the source and destination are in expected - # subdomains. - if ! [[ $SOURCE_URL =~ ^https://(community|help)\.expensify\.com ]]; then - error "Found source URL that is not a communityDot or helpDot URL: $SOURCE_URL" - exit 1 - fi - - if ! [[ $DEST_URL =~ ^https://(help|use)\.expensify\.com ]]; then - error "Found destination URL that is not a helpDot or useDot URL: $DEST_URL" - exit 1 - fi - - info "Source: $SOURCE_URL and destination: $DEST_URL appear to be formatted correctly." - ITEMS_TO_ADD+=("$line") # This line skips the first line in the csv because the first line is a header row. @@ -83,6 +57,9 @@ done | jq -n '. |= [inputs]') info "Adding redirects for $PUT_JSON" +# Dump $PUT_JSON into a file otherwise the curl request below will fail with too many arguments +echo "$PUT_JSON" > redirects.json + # We use PUT here instead of POST so that we replace the entire list in place. This has many benefits: # 1. We don't have to check if items are already in the list, allowing this script to run faster # 2. We can support deleting redirects this way by simply removing them from the list @@ -93,7 +70,7 @@ info "Adding redirects for $PUT_JSON" PUT_RESULT=$(curl -s --request PUT --url "https://api.cloudflare.com/client/v4/accounts/$ZONE_ID/rules/lists/$LIST_ID/items" \ --header 'Content-Type: application/json' \ --header "Authorization: Bearer $CLOUDFLARE_LIST_TOKEN" \ - --data "$PUT_JSON") + --data-binary @redirects.json) checkCloudflareResult "$PUT_RESULT" OPERATION_ID=$(echo "$PUT_RESULT" | jq -r .result.operation_id) diff --git a/.github/scripts/verifyRedirect.sh b/.github/scripts/verifyRedirect.sh index b8942cd5b23d..3d96ba17a799 100755 --- a/.github/scripts/verifyRedirect.sh +++ b/.github/scripts/verifyRedirect.sh @@ -3,7 +3,10 @@ # HelpDot - Verifies that redirects.csv does not have any duplicates # Duplicate sourceURLs break redirection on cloudflare pages +source scripts/shellUtils.sh + declare -r REDIRECTS_FILE="docs/redirects.csv" +declare -a ITEMS_TO_ADD declare -r RED='\033[0;31m' declare -r GREEN='\033[0;32m' @@ -22,5 +25,44 @@ if [[ DETECT_CYCLE_EXIT_CODE -eq 1 ]]; then exit 1 fi +while read -r line; do + # Split each line of the file into a source and destination so we can sanity check + # and compare against the current list. + read -r -a LINE_PARTS < <(echo "$line" | tr ',' ' ') + SOURCE_URL=${LINE_PARTS[0]} + DEST_URL=${LINE_PARTS[1]} + + # Make sure the format of the line is as expected. + if [[ "${#LINE_PARTS[@]}" -gt 2 ]]; then + error "Found a line with more than one comma: $line" + exit 1 + fi + + # Basic sanity checking to make sure that the source and destination are in expected + # subdomains. + if ! [[ $SOURCE_URL =~ ^https://(community|help)\.expensify\.com ]] || [[ $SOURCE_URL =~ \# ]]; then + error "Found source URL that is not a communityDot or helpDot URL, or contains a '#': $SOURCE_URL" + exit 1 +fi + + if ! [[ $DEST_URL =~ ^https://(help|use|integrations)\.expensify\.com|^https://www\.expensify\.org ]]; then + error "Found destination URL that is not a supported URL: $DEST_URL" + exit 1 + fi + + info "Source: $SOURCE_URL and destination: $DEST_URL appear to be formatted correctly." + + ITEMS_TO_ADD+=("$line") + +# This line skips the first line in the csv because the first line is a header row. +done <<< "$(tail +2 $REDIRECTS_FILE)" + +# Sanity check that we should actually be running this and we aren't about to delete +# every single redirect. +if [[ "${#ITEMS_TO_ADD[@]}" -lt 1 ]]; then + error "No items found to add, why are we running?" + exit 1 +fi + echo -e "${GREEN}The redirects.csv is valid!${NC}" exit 0 diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index 88437745b9ac..83fa80a2cb73 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -9,7 +9,7 @@ env: SHOULD_DEPLOY_PRODUCTION: ${{ github.event.action == 'released' }} concurrency: - group: ${{ github.workflow }}-${{ github.event_name }} + group: ${{ github.workflow }}-${{ github.event.action }} cancel-in-progress: true jobs: @@ -38,6 +38,7 @@ jobs: secrets: inherit android: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly name: Build and deploy Android needs: validateActor if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} @@ -122,6 +123,7 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} desktop: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly name: Build and deploy Desktop needs: validateActor if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} @@ -165,6 +167,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} iOS: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly name: Build and deploy iOS needs: validateActor if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} @@ -276,6 +279,7 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} web: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly name: Build and deploy Web needs: validateActor if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} @@ -330,6 +334,7 @@ jobs: - name: Verify staging deploy if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} run: | + sleep 5 DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://staging.new.expensify.com/version.json | jq -r '.version')" if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." @@ -339,6 +344,7 @@ jobs: - name: Verify production deploy if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} run: | + sleep 5 DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://new.expensify.com/version.json | jq -r '.version')" if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index da4225f0e4be..5de11ba40a59 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -54,8 +54,7 @@ jobs: id: getHeadRef run: | set -e - gh pr checkout ${{ github.event.inputs.PULL_REQUEST_NUMBER }} - echo "REF=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + echo "REF=$(gh pr view ${{ github.event.inputs.PULL_REQUEST_NUMBER }} --json headRefOid --jq '.headRefOid')" >> "$GITHUB_OUTPUT" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/android/app/build.gradle b/android/app/build.gradle index db98853cb508..e407b3324a88 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -108,8 +108,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002004 - versionName "9.0.20-4" + versionCode 1009002400 + versionName "9.0.24-0" // 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" diff --git a/assets/emojis/en.ts b/assets/emojis/en.ts index adac235f56ce..a246d51c41bc 100644 --- a/assets/emojis/en.ts +++ b/assets/emojis/en.ts @@ -144,7 +144,7 @@ const enEmojis: EmojisList = { keywords: ['meh', 'face', 'unhappy'], }, '🙄': { - keywords: ['eyes', 'face', 'rolling'], + keywords: ['eyes', 'face', 'rolling', 'eyeroll'], }, '😬': { keywords: ['face', 'grimace'], diff --git a/assets/images/box.svg b/assets/images/box.svg index ba0b3c22d8a0..05f808e801ee 100644 --- a/assets/images/box.svg +++ b/assets/images/box.svg @@ -1,3 +1 @@ - - - + \ No newline at end of file diff --git a/assets/images/feed.svg b/assets/images/feed.svg new file mode 100644 index 000000000000..2fd03eeadd00 --- /dev/null +++ b/assets/images/feed.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/product-illustrations/todd-with-phones.svg b/assets/images/product-illustrations/todd-with-phones.svg index 5992a4f408d7..21ee5a015820 100644 --- a/assets/images/product-illustrations/todd-with-phones.svg +++ b/assets/images/product-illustrations/todd-with-phones.svg @@ -1,667 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/advanced-approvals-icon-square.svg b/assets/images/simple-illustrations/advanced-approvals-icon-square.svg index 00f3de51bd42..bd71512a9846 100644 --- a/assets/images/simple-illustrations/advanced-approvals-icon-square.svg +++ b/assets/images/simple-illustrations/advanced-approvals-icon-square.svg @@ -1,86 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/emptystate__big-vault.svg b/assets/images/simple-illustrations/emptystate__big-vault.svg index 02606e39fafd..a1d18da1b117 100644 --- a/assets/images/simple-illustrations/emptystate__big-vault.svg +++ b/assets/images/simple-illustrations/emptystate__big-vault.svg @@ -1,378 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__rules.svg b/assets/images/simple-illustrations/simple-illustration__rules.svg new file mode 100644 index 000000000000..6432f26d9ac6 --- /dev/null +++ b/assets/images/simple-illustrations/simple-illustration__rules.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/user-check.svg b/assets/images/user-check.svg index 2da67de751f4..931f4e5f6a51 100644 --- a/assets/images/user-check.svg +++ b/assets/images/user-check.svg @@ -1,9 +1 @@ - - - - + \ No newline at end of file diff --git a/contributingGuides/CONTRIBUTING.md b/contributingGuides/CONTRIBUTING.md index 61baec9d9f1c..eab59a65d003 100644 --- a/contributingGuides/CONTRIBUTING.md +++ b/contributingGuides/CONTRIBUTING.md @@ -37,6 +37,8 @@ If you've found a vulnerability, please email security@expensify.com with the su ## Payment for Contributions We hire and pay external contributors via [Upwork.com](https://www.upwork.com). If you'd like to be paid for contributing, please create an Upwork account, apply for an available job in [GitHub](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22), and finally apply for the job in Upwork once your proposal gets selected in GitHub. Please make sure your Upwork profile is **fully verified** before applying, otherwise you run the risk of not being paid. If you think your compensation should be increased for a specific job, you can request a reevaluation by commenting in the Github issue where the Upwork job was posted. +Please add your Upwork profile link in your GitHub Bio to help ensure prompt payment. If you're using Slack or Expensify for discussions, please add your Upwork profile link **and** your GitHub username in your Slack Title and Expensify Status. + Payment for your contributions will be made no less than 7 days after the pull request is deployed to production to allow for [regression](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#regressions) testing. If you have not received payment after 8 days of the PR being deployed to production, and there are no [regressions](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#regressions), please add a comment to the issue mentioning the BugZero team member (Look for the melvin-bot "Triggered auto assignment to... (`Bug`)" to see who this is). New contributors are limited to working on one job at a time, **do not submit proposals for new jobs until your first PR has been merged**. Experienced contributors may work on numerous jobs simultaneously. diff --git a/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account.md b/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account.md index 99b904b23344..1ad70117ed5c 100644 --- a/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account.md +++ b/docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account.md @@ -96,7 +96,7 @@ If you do not see these test transactions after two business days, click the gre {% include faq-begin.md %} -**I received a “something’s gone wrong” error while trying to add my ID to Onfido.** +### I received a “something’s gone wrong” error while trying to add my ID to Onfido. If you receive an error message during this process, check all of the following: - Ensure you are using either the Safari (on iPhone) or Chrome (on Android) browser. @@ -108,17 +108,17 @@ If you receive an error message during this process, check all of the following: If the issue persists, follow these steps on a different device, if possible. Contact your Account Manager or Concierge for further troubleshooting assistance. -**Should I add a Beneficial Owner if our business is owned by another company?** +### Should I add a Beneficial Owner if our business is owned by another company? No, you should only indicate that you have a Beneficial Owner if an individual owns 25% or more of the business. -**Why can’t I input my address or upload my ID?** +### Why can’t I input my address or upload my ID? Ensure that the address you’re entering is in the United States. When adding a verified business bank account in Expensify, the individual adding the account and any beneficial owners are required to have a U.S. address, photo ID, and SSN. If you do not meet these requirements, you’ll need to have another admin add the bank account and share access with you once the account is verified. -**Why am I being asked for documentation when adding my bank account?** +### Why am I being asked for documentation when adding my bank account? When a bank account is added to Expensify, we conduct a series of checks to comply with both our sponsor bank’s requirements and federal government regulations for the Bank Secrecy Act (BSA), Anti-Money Laundering (AML) laws, and anti-fraud. @@ -126,26 +126,44 @@ If automatic verification fails, we may request manual verification, which could If you have any questions regarding the documentation request you received, contact Concierge for additional assistance. -**I don’t see all three microtransactions I need to validate my bank account.** +### What should I do if I don’t see all three microtransactions needed to validate my bank account? If you do not see the three microtransactions by the end of the second business day, contact your bank and ask them to whitelist Expensify’s ACH IDs 1270239450 and 4270239450. Expensify’s ACH Originator Name is “Expensify.” Once you are whitelisted, contact your Account Manager or Concierge, and our team will re-trigger the three transactions. -**What happens if my bank requires an additional security check before adding it to a third party?** +### What happens if my bank requires an additional security check before adding it to a third party? If your bank account has two-factor authentication (2FA) or another security step enabled, you should be prompted to complete this authentication step when connecting the account to Expensify. However, if you encounter an error during this process, you can close the pop-up window and select Connect Manually to add the account manually. -**I added a business deposit account. Can I also pay employees from this account?** +### I added a business deposit account. Can I also pay employees from this account? To pay employees from a business deposit account, click **Verify** next to the bank account. This will take you through the additional verification steps required to make this account a verified business bank account that you can use to issue payments. -**I connected my business deposit account. Why haven’t I received my reimbursement?** +### I connected my business deposit account. Why haven’t I received my reimbursement? There are a few reasons why you might not have received a reimbursement: - The estimated deposit date on the report has not arrived yet. - The bank account information is incorrect. If you believe you may have entered the wrong account, contact the Concierge and provide the Report ID for the missing reimbursement. -- Your account wasn’t set up for Direct Deposit/ACH. You can contact your bank to confirm. +- Your account wasn’t set up for Direct Deposit/ACH. Please contact your bank to confirm. + +### Are there certain industries or businesses for which Expensify cannot process payments? + +There are! If your business is associated with one of the following industries, you won't be able to connect your business bank account to process payments: +- Security Brokers & Dealers +- Dating & Escort Services +- Massage Parlors +- Casinos & Gambling/Betting Services +- Non-FI, Money Orders +- Wires, Money Orders +- Government Owned Lotteries +- Government Licensed Online Casinos (Online Gambling) +- Government Licensed Horse/Dog Racing +- Crypto-currency businesses +- Internet gambling +- Marijuana-related businesses +- Firearm-related businesses (manufacturing and selling) +- NFT (non-fungible token) services {% include faq-end.md %} diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Configure-Quickbooks-Desktop.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Configure-Quickbooks-Desktop.md index 18b8a9ec31f9..d3dcda91ffcc 100644 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Configure-Quickbooks-Desktop.md +++ b/docs/articles/expensify-classic/connections/quickbooks-desktop/Configure-Quickbooks-Desktop.md @@ -2,87 +2,101 @@ title: Configure Quickbooks Desktop description: Configure Quickbooks Desktop --- -# How to configure export settings for QuickBooks Desktop -To Configure Settings, go to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** and click **Configure**. Click on the Export tab. +Our new QuickBooks Desktop integration allows you to automate the import and export process with Expensify. -## Preferred Exporter -This person is used in QuickBooks Desktop as the export user. They will also receive notifications for errors. +# Step 1: Configure export settings +The following steps will determine how data will be exported from Expensify to QuickBooks Desktop. -## Date -Choose either the report's submitted date, the report's exported date, or the date of the last expense on the report when exporting reports to QuickBooks Desktop. +1. In Expensify, hover over **Settings** and click **Workspaces**. +2. Select the Workspace you want to connect to QuickBooks Desktop. +3. Click the **Connections** tab. +4. Click **Export** under the QuickBooks Desktop connection. +5. Review each of the following export settings: +- **Preferred Exporter**: This person is used in QuickBooks Desktop as the export user. They will receive notifications for errors, as well as prompts to export reports via the Home page of their Expensify account. +- **Date**: You can choose either the report’s submitted date, the report’s exported date, or the date of the last expense on the report when exporting reports to QuickBooks Desktop. +- **Unique reference numbers**: Enable this to allow the use of a unique reference number for each transaction. Disable this to use the same Report ID for all expenses from a certain report. +- **Reimbursable expenses**: Reimbursable options include: + - **Vendor Bill (recommended)**: A single itemized vendor bill for each Expensify report. An A/P account is required to export to a vendor bill. + - **Check**: A single itemized check for each Expensify report. + - **Journal Entry**: A single itemized journal entry for each Expensify report. +- **Non-reimbursable expenses**: Non-reimbursable options include: + - **Vendor Bill**: Each Expensify report results in a single itemized vendor bill. The bill is associated with the “vendor,” which is the individual responsible for creating or submitting the report in Expensify. + - **Credit Card expenses**: Each expense appears as a separate credit card transaction with a post date that matches your credit card statement. If you centrally manage company cards through your domain, you can export expenses from each card to a specific QuickBooks account by clicking Edit Exports next to each user’s card. To display the merchant name in the payee field in QuickBooks Desktop, ensure that a matching Vendor exists in QuickBooks. Expensify searches for an exact match during export. If no match is found, the payee is mapped to a Credit Card Misc. Vendor created by Expensify. + - **Debit Card expenses**: Expenses are exported as individual itemized checks for each Expensify report. The check is written to the “vendor,” which is the person who created or submitted the report in Expensify. -## Use unique reference numbers -Enable this to allow use of a unique reference number for each transaction. Disable this to use the same Report ID for all expenses from a certain report. +# Step 2: Configure coding/import settings -## Reimbursable expenses -* **Vendor Bill (recommended):** A single itemized vendor bill for each Expensify report. An A/P account is required to export to a vendor bill. -* **Check:** A single itemized check for each Expensify report. -* **Journal Entry:** A single itemized journal entry for each Expensify report. - * When exporting as journal entries to an Accounts Payable, this requires a vendor record, not an employee. The vendor record must have the email address of the report creator/submitter. - * If the report creator/submitter also has an employee record, you need to remove the email, because Expensify will try to export to the employee record first for journal entries. +The following steps help you determine how data will be imported from QuickBooks Online to Expensify: -**Note on negative expenses:** In general, you can export negative expenses successfully to QuickBooks Desktop regardless of which export option you choose. The one thing to keep in mind is that if you have Check selected as your export option, the total of the report can not be negative. +1. Click Import under the QuickBooks Online connection. +2. Review each of the following import settings: +- **Chart of Accounts**: The Chart of Accounts is automatically imported from QuickBooks Desktop as categories. This cannot be amended. +- **Classes**: Choose whether to import classes, which will be shown in Expensify as tags for expense-level coding. +- **Customers/Projects**: Choose whether to import customers/projects, which will be shown in Expensify as tags for expense-level coding. +- **Locations**: Choose whether to import locations, which will be shown in Expensify as tags for expense-level coding. -**Note on exporting to Employee Records:** If you want to export reports to your users' Employee Records instead of their Vendor Records, you will need to select Check or Journal Entry for your reimbursable export option. There isn't a way to export as a Vendor Bill to an Employee Record. If you are setting up Expensify users as employees, you will need to activate QuickBooks Desktop Payroll to view the Employee Profile tab where submitter's email addresses need to be entered. +# Step 3: Configure advanced settings +The following steps help you determine the advanced settings for your connection, like auto-sync and employee invitation settings. -## Non-reimbursable expenses -**Credit Card Expenses:** -* Each expense will appear as a separate credit card transaction. -* The posting date will match your credit card statement. -* To display the merchant name in the payee field in QuickBooks Desktop, ensure that a matching Vendor exists in QuickBooks. Expensify searches for an exact match during export. If no match is found, the payee is mapped to a **Credit Card Misc.** Vendor created by Expensify. -* If you're centrally managing company cards through Domain Control, you can export expenses from each card to a specific QuickBooks account (detailed instructions available). - -**Debit Card Expenses:** -* Expenses export as individual itemized checks for each Expensify report. -* The check is written to the "vendor," which is the person who created or submitted the report in Expensify. +1. Click **Advanced** under the QuickBooks Desktop connection. +2. **Enable or disable Auto-Sync**: If enabled, QuickBooks Desktop automatically communicates changes with Expensify to ensure that the data shared between the two systems is up to date. New report approvals/reimbursements will be synced during the next auto-sync period. -**Vendor Bill:** -* Each Expensify report results in a single itemized vendor bill. -* The bill is associated with the "vendor," which is the individual responsible for creating or submitting the report in Expensify. +# FAQ -# How to configure coding for QuickBooks Desktop -To Configure Settings, go to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** and click **Configure**. Click on the Coding tab. +## **How do I manually sync my QuickBooks Desktop if I have Auto-Sync disabled?** -## Categories -Expensify's integration with QuickBooks brings in your Chart of Accounts as Categories in Expensify automatically. Here's how to manage them: -1. After connecting, go to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Categories** to view the accounts imported from QuickBooks Desktop. -2. You can use the enable/disable button to choose which Categories your employees can access. Additionally, you can set specific rules for each Category via the blue settings cog. -3. Expensify offers Auto-Categorization to automatically assign expenses to the appropriate expense categories. -4. If needed, you can edit the names of the imported Categories to simplify expense coding for your employees. Keep in mind that if you make changes to these accounts in QuickBooks Desktop, the category names in Expensify will update to match them during the next sync. -5. _**Important:**_ Each expense must have a category selected to export to QuickBooks Desktop. The selected category must be one imported from QuickBooks Desktop; you cannot manually create categories within Expensify policy settings. +To manually sync your connection: -## Classes -Classes can be imported from QuickBooks as either tags (line-item level) or report fields (header level). +1. In Expensify, hover over **Settings** and select **Workspaces**. +2. Click the Workspace name that is connected to QuickBooks Desktop. +3. Click the **Connections** tab on the left. +4. Click **Sync Now** under QuickBooks Desktop. -## Customers/Projects -You can bring in Customers/Projects from QuickBooks into Expensify in two ways: as tags (at the line-item level) or as report fields (at the header level). If you're utilizing Billable Expenses in Expensify, here's what you need to know: -* Customers/Projects must be enabled if you're using Billable Expenses. -* Expenses marked as "Billable" need to be tagged with a Customer/Project to successfully export them to QuickBooks. +{% include info.html %} +For manual syncing, we recommend completing this process at least once a week and/or after making changes in QuickBooks Desktop that could impact how reports export from Expensify. Changes may include adjustments to your chart of accounts, vendors, employees, customers/jobs, or items. Remember: Both the Web Connector and QuickBooks Desktop need to be running for syncing or exporting to work. +{% include end-info.html %} -## Items -Items can be imported from QuickBooks as categories alongside your expense accounts. +## **Can I sync Expensify and QuickBooks Desktop (QBD) and use the platforms at the same time?** -{% include faq-begin.md %} -## How do I sync my connection? -1. Ensure that both the Expensify Sync Manager and QuickBooks Desktop are running. -2. On the Expensify website, navigate to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** > **QuickBooks Desktop**, and click **Sync now**. -3. Wait for the syncing process to finish. Typically, this takes about 2-5 minutes, but it might take longer, depending on when you last synced and the size of your QuickBooks company file. The page will refresh automatically once syncing is complete. +When syncing Expensify to QuickBooks Desktop, we recommend waiting until the sync finishes to access either Expensify and/or QuickBooks Desktop, as performance may vary during this process. You cannot open an instance of QuickBooks Desktop while a program is syncing - this may cause QuickBooks Desktop to behave unexpectedly. -We recommend syncing at least once a week or whenever you make changes in QuickBooks Desktop that could impact how your reports export from Expensify. Changes could include adjustments to your Chart of Accounts, Vendors, Employees, Customers/Jobs, or Items. Remember, both the Sync Manager and QuickBooks Desktop need to be running for syncing or exporting to work. +## **What are the different types of accounts that can be imported from Quickbooks Desktop?** -## How do I export reports? -The Sync Manager and QuickBooks Desktop both need to be running in order to sync or export. -* **Exporting an Individual Report:** You can export reports to QuickBooks Desktop one at a time from within an individual report on the Expensify website by clicking the "Export to" button. -* **Exporting Reports in Bulk:** To export multiple reports at a time, select the reports that you'd like to export from the Reports page on the website and click the "Export to" button near the top of the page. +Here is the list of accounts from QuickBooks Desktop and how they are pulled into Expensify: -Once reports have been exported to QuickBooks Desktop successfully, you will see a green QuickBooks icon next to each report on the Reports page. You can check to see when a report was exported in the Comments section of the individual report. +| QBD account type | How it imports to Expensify | +| ------------- | ------------- | +| Accounts payable | Vendor bill or journal entry export options | +| Accounts receivable | Do not import | +| Accumulated adjustment | Do not import | +| Bank | Debit card or check export options | +| Credit card | Credit card export options | +| Equity | Do not import | +| Fixed assets | Categories | +| Income | Do not import | +| Long-term liabilities | Do not import | +| Other assets | Do not import | +| Other current assets | Categories or journal entry export options | +| Other current liabilities | Journal Entry export options if the report creator is set up as an Employee within QuickBooks | +| Other expense | All detail types except Exchange Gain or Loss import as categories; Exchange Gain or Loss does not import | +| Other income | Do not import | -## Can I export negative expenses? -Generally, you can export negative expenses to QuickBooks Desktop successfully, regardless of your option. However, please keep in mind that if you have *Check* selected as your export option, the report's total cannot be negative. +## **Why are exports showing as “Credit Card Misc.”?** + +When exporting as credit or debit card expenses, Expensify checks for an exact vendor match. If none are found, the payee will be mapped to a vendor that Expensify will automatically create and label as Credit Card Misc. or Debit Card Misc. + +If you centrally manage your company cards through domains, you can export expenses from each card to a specific account in QuickBooks: + +1. In Expensify, hover over Settings and click Domains. +2. Select the desired domain. +3. Click the **Company Cards** tab. +4. Click **Export**. + +## **How does multi-currency work with QuickBooks Desktop?** -## How does multi-currency work with QuickBooks Desktop? When using QuickBooks Desktop Multi-Currency, there are some limitations to consider based on your export options: -1. **Vendor Bills and Checks:** The currency of the vendor and the currency of the account must match, but they do not have to be in the home currency. -2. **Credit Card:** If an expense doesn't match an existing vendor in QuickBooks, it exports to the **Credit Card Misc.** vendor created by Expensify. When exporting a report in a currency other than your home currency, the transaction will be created under the vendor's currency with a 1:1 conversion. For example, a transaction in Expensify for $50 CAD will appear in QuickBooks as $50 USD. -3. **Journal Entries:** Multi-currency exports will fail because the account currency must match both the vendor currency and the home currency. + +- **Vendor Bills and Checks**: The currency of the vendor and the currency of the account must match, but they do not have to be in the home currency. +- **Credit Card**: If an expense doesn’t match an existing vendor in QuickBooks, it exports to the Credit Card Misc. vendor created by Expensify. When exporting a report in a currency other than your home currency, the transaction will be created under the vendor’s currency with a 1:1 conversion. For example, a transaction in Expensify for $50 CAD will appear in QuickBooks as $50 USD. +- **Journal Entries**: Multi-currency exports will fail because the account currency must match both the vendor currency and the home currency. diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop.md index 92e1e4dd841f..50e3e0971869 100644 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop.md +++ b/docs/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop.md @@ -4,59 +4,95 @@ description: Connect Expensify to QuickBooks Desktop order: 1 --- # Overview -To connect Expensify to QuickBooks Desktop, use Right Networks as the hosting platform if possible. Right Networks is a cloud-based service that was built specifically for this integration. If you need a Right Networks account, complete [this form](https://info.rightnetworks.com/partner-expensify) to start the process. +QuickBooks Desktop is an accounting package developed by Intuit. It is designed for small and medium-sized businesses to help them manage their financial and accounting tasks. You can connect Expensify to QuickBooks Desktop to make expense management seamless. -**A couple of notes before connecting QuickBooks Desktop to Expensify:** -- Make sure you're logged into QuickBooks Desktop as an admin -- Check that the company file you want to connect Expensify to is the only one open +# Connect to QuickBooks Desktop +{% include info.html %} +To connect QuickBooks Desktop to Expensify, you must log into QuickBooks Desktop as an Admin, and the company file that you want to connect to Expensify must be the only one that is open. +{% include end-info.html %} -# Connect to QuickBooks Desktop +1. In Expensify, hover over **Settings** and click on **Workspaces**. +2. Select the workspace you want to connect to QuickBooks Desktop. +3. Click the **Connections** tab. +4. Click **Connect to QuickBooks Desktop**. +5. Click Copy to copy the link, then paste the link into the computer where QuickBooks Desktop is running. + +![QuickBooks Desktop Setup pop-up link, containing the URL to paste](https://help.expensify.com/assets/images/QBO_desktop_01.png){:width="100%"} + +6. Select the version of QuickBooks Desktop that you currently have. + +![The Web Connnector Pop-up to allow you to select the type of QuickBooks Desktop you have](https://help.expensify.com/assets/images/QBO_desktop_02.png){:width="100%"} + +7. Download the Web Connector and go through the guided installation process. +8. Open the Web Connector. +9. Click on **Add an Application**. + +![The Web Connnector Pop-up where you will need to click on Add an Application](https://help.expensify.com/assets/images/QBO_desktop_03.png){:width="100%"} + +{% include info.html %} +For this step, it is key to ensure that the correct company file is open in QuickBooks Desktop and that it is the only one open. +{% include end-info.html %} + +10. In QuickBooks Desktop, select **"Yes, always allow access, even when QuickBooks is not running"** and click **Continue**. + +![The QuickBooks Desktop pop-up, where you will need to select "Yes, always allow access, even when QuickBooks is not running"](https://help.expensify.com/assets/images/QBO_desktop_04.png){:width="100%"} + +11. Click **OK**, then click **Yes**. + +![The QuickBooks Desktop pop-up, where you will need to click "Ok" then select "Yes"](https://help.expensify.com/assets/images/QBO_desktop_05.png){:width="100%"} + +12. Click **Copy** to copy the password. + +![The Web Connector pop-up, where you will need to click "Copy"](https://help.expensify.com/assets/images/QBO_desktop_06.png){:width="100%"} + +13. Paste the password into the Password field of the Web Connector and press **Enter**. + +![The Web Connector pop-up, where you will need to paste the password into the password field](https://help.expensify.com/assets/images/QBO_desktop_08.png){:width="100%"} + +14. Click **Yes** to save the password. The new connection now appears in the Web Connector. + +![The Web Connector pop-up, where you will need to click "Yes"](https://help.expensify.com/assets/images/QBO_desktop_07.png){:width="100%"} + +# FAQ + +## What are the hardware and software requirements for the QuickBooks Desktop connector? + +- Hardware requirements: You will need to ensure that the host machine meets [Intuit's recommended specifications](https://quickbooks.intuit.com/learn-support/en-us/help-article/install-products/system-requirements-quickbooks-desktop-2022/L9664spDA_US_en_US) for running QuickBooks Desktop. +- Software requirements: Windows 10 or Windows 11 with the latest service pack(s) installed. Users have successfully run the connector on older versions of Windows; however, we do not officially support this due to Microsoft's withdrawal of support for these operating systems. The web connector will not run on Mac OS. + +## What versions of QuickBooks Desktop are supported? + +Expensify’s QuickBooks Desktop integration follows [Intuit’s service discontinuation policy](https://quickbooks.intuit.com/learn-support/en-us/help-article/feature-preferences/quickbooks-desktop-service-discontinuation-policy/L17cXxlie_US_en_US) for QuickBooks Desktop and fully supports the following versions, version tiers, and special editions: + +- The latest three versions of: + + - QuickBooks Desktop (US) + - QuickBooks Desktop (Canada) + +- Version tiers: + + - Accountant + - Pro + - Pro Plus + - Premier + - Premier Plus + - Enterprise + +- Special editions: + + - Contractor edition + - Manufacturing and Wholesale edition + - Accountant edition + - Professional Services edition + - Nonprofit edition + +## Can multiple QuickBooks Desktop Connectors be installed on the same machine? + +Yes. You must have one connector per company file, but you can install multiple QuickBooks Desktop Connectors to sync multiple company files to Expensify from the same computer. + +If syncing multiple companies, make sure you’re logged in to the correct QuickBooks company file when syncing between QuickBooks and Expensify. + +## Can I export negative expenses? -## Step 1: Set up submitters in QuickBooks Desktop -- Make sure all report submitters are set up as Vendors in QuickBooks Desktop and their Expensify email is in the "Main Email" field of their Vendor record. You can do this in the vendor section of QuickBooks. -- If you want to export reports to your users' employee records instead of vendor records, select Check or Journal Entry as your reimbursable export option. -- To set up Expensify users as employees, activate QuickBooks Desktop Payroll. This module is necessary to access the Employee Profile tab, where you can enter the submitter's email addresses. - -## Step 2: Enable/install the Expensify Sync Manager -1. Navigate to **Settings > Workspaces > Group > [Workspace Name] > Connections** -2. Click **Connect to QuickBooks Desktop** to initiate the connection - -**Option 1: Enable the Expensify Sync Manager in Right Networks (recommended)** -- For this option, **single-user mode** in QuickBooks Desktop is required. -- If you don't have an account with Right Networks, you can contact Right Networks [here](https://info.rightnetworks.com/partner-expensify) -- Once set up, you can enable the Expensify Sync Manager from the **My Account** section in Right Networks' portal - -**Option 2: Install the Expensify Sync Manager on Your Third-Party Remote Desktop.** -To download the Sync Manager to your desktop, you must contact your third-party remote desktop provider and request permission. They might have security restrictions, so it's best to communicate with them directly to avoid potential problems with the Sync Manager. Remember that the Sync Manager program file should be stored in the same location (i.e., the same drive) as your QuickBooks Desktop program. - -## Step 3: Complete the connection -1. Open QuickBooks and access the desired Company File using the QuickBooks Admin credentials (admin credentials are necessary for creating the connection) -2. Navigate to **Settings > Workspaces > Group > [Workspace Name] > Connections** -3. Copy the Token by selecting the copy icon -4. While QuickBooks is still running, launch the Expensify Sync Manager by pasting the Token into the Sync Manager -5. Click **Save** -6. Once the Sync Manager status displays **Connected**, return to Expensify and click **Continue** - -## Step 4: Allow access -1. Return to QuickBooks where you'll see an **Application Certificate** screen - - On the first page of the Certificate screen, click **Yes, always; allow access even if QuickBooks is not running** -3. Click **Continue** -4. On the second page of the Certificate screen, choose the Admin user from the dropdown menu -5. Click **Done** -7. Return to Expensify and wait for the sync to complete - -{% include faq-begin.md %} - -## After connecting, how do I sync QuickBooks and Expensify? -1. Confirm that both the Expensify Sync Manager and QuickBooks Desktop are running -2. On the Expensify website, navigate to **Settings > Workspaces > Group > [Workspace Name] > Connections**, and click **Sync now** -3. Wait for the sync to complete - -Typically, this takes about 2-5 minutes, but it might take longer, depending on when you last synced and the size of your QuickBooks company file. The page will refresh automatically once syncing is complete. - -We recommend syncing at least once a week or whenever you make changes in QuickBooks Desktop that could impact how your reports export from Expensify. Changes could include adjustments to your Chart of Accounts, Vendors, Employees, Customers/Jobs, or Items. - -Remember, both the Sync Manager and QuickBooks Desktop need to be running for syncing or exporting to work. - -{% include faq-end.md %} +Generally, yes. However, if you have Check selected as your export option, the report’s total cannot be negative. This also applies to non-reimbursable expenses exported as debit card transactions. Because QuickBooks Desktop does not have debit card functionality, the transactions export as a non-reimbursable check, which must have a positive total amount. diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md index 061b01b7a924..09afd2e4e7f2 100644 --- a/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md +++ b/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md @@ -3,43 +3,89 @@ title: Quickbooks Desktop Troubleshooting description: Quickbooks Desktop Troubleshooting --- -# Sync and export errors -## Error: No Vendor Found For Email in QuickBooks -To address this issue, ensure that each submitter's email is saved as the **Main Email** in their Vendor record within QuickBooks Desktop. Here's how to resolve it: -1. Go to your Vendor section in QuickBooks. -2. Verify that the email mentioned in the error matches the **Main Email** field in the respective vendor's record. It's important to note that this comparison is case-sensitive, so ensure that capitalization matches as well. -3. If you prefer to export reports to your users' employee records instead of their vendor records, select either **Check** or **Journal Entry** as your reimbursable export option. If you are setting up Expensify users as employees, activate QuickBooks Desktop Payroll to access the Employee Profile tab where submitter email addresses need to be entered. -4. Once you've added the correct email to the vendor record, save this change, and then sync your policy before attempting to export the report again. - -## Error: Do Not Have Permission to Access Company Data File -To resolve this error, follow these steps: -1. Log into QuickBooks Desktop as an Admin in single-user mode. -2. Go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**. -3. Select the Expensify Sync Manager and click on **Properties**. -4. Ensure that **Allow this application to login automatically** is checked, and then click **OK**. Close all windows within QuickBooks. -5. If you still encounter the error after following the above steps, go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**, and remove the Expensify Sync Manager from the list. -6. Next, attempt to sync your policy again in Expensify. You'll be prompted to re-authorize the connection in QuickBooks. -7. Click **Yes, always; allow access even if QuickBooks is not running.** -8. From the dropdown, select the Admin user, and then click **Continue**. Note that selecting **Admin** here doesn't mean you always have to be logged in as an admin to use the connection; it's just required for setting up the connection. -9. Click **Done** on the pop-up window and return to Expensify, where your policy should complete the syncing process. - -## Error: The Wrong QuickBooks Company is Open. -This error suggests that the wrong company file is open in QuickBooks Desktop. To resolve this issue, follow these steps: -1. First, go through the general troubleshooting steps as outlined. -2. If you can confirm that the incorrect company file is open in QuickBooks, go to QuickBooks and select **File** > **Open or Restore Company** > _[Company Name]_ to open the correct company file. After doing this, try syncing your policy again. -3. If the correct company file is open, but you're still encountering the error, completely close QuickBooks Desktop, reopen the desired company file and then attempt to sync again. -4. If the error persists, log into QuickBooks as an admin in single-user mode. Then, go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences** and remove the Expensify Sync Manager from the list. -5. Next, try syncing your policy again in Expensify. You'll be prompted to re-authorize the connection in QuickBooks, allowing you to sync successfully. -6. If the error continues even after trying the steps above, double-check that the token you see in the Sync Manager matches the token in your connection settings. - -## Error: The Expensify Sync Manager Could Not Be Reached. -To resolve this error, follow these steps: -*Note: You must be in single-user mode to sync.* - -1. Ensure that both the Sync Manager and QuickBooks Desktop are running. -2. Confirm that the Sync Manager is installed in the correct location. It should be in the same location as your QuickBooks application. If QuickBooks is on your local desktop, the Sync Manager should be there, too. If QuickBooks is on a remote server, install the Sync Manager there. -Verify that the Sync Manager's status is **Connected**. -3. If the Sync Manager status is already **Connected**, click **Edit** and then *Save* to refresh the connection. Afterwards, try syncing your policy again. -4. If the error persists, double-check that the token you see in the Sync Manager matches the token in your connection settings. - -{% include faq-end.md %} +# The Web Connector cannot be reached + +Generally, these errors indicate that there is a connection issue, where there’s a breakdown between Expensify and QuickBooks. + +## How to resolve + +1. Make sure that the Web Connector and QuickBooks Desktop are both running. +2. Make sure that the Web Connector is installed in the same location as your QuickBooks application. For example, if QuickBooks is installed on your local desktop, the Web Connector should be too. Or if QuickBooks is installed on a remote server, the Web Connector should be installed there as well. + +If the error persists: + +1. Close the Web Connector completely (you may want to use Task Manager to do this). +2. Right-click the Web Connector icon on your desktop and select **Run as administrator**. +3. Sync your Workspace again. + +If this doesn’t work, the final troubleshooting steps should be: + +1. Quit QuickBooks Desktop, then reopen it. +2. In Expensify, hover over **Settings** and select **Workspaces**. +3. Click the workspace name that is connected to QuickBooks Desktop. +4. Click the **Connections** tab on the left. +5. Click **QuickBooks Desktop**. +6. Click **Sync Now**. +7. If this still doesn’t resolve the issue, use the link to reinstall the Web Connector. + +# Connection and/or authentication issue + +Generally, these errors indicate that there is a credentials issue. + +## How to resolve + +1. Make sure QuickBooks Desktop is open with the correct company file. This must be the same company file that you have connected to Expensify. +2. Make sure the QuickBooks Web Connector is open and the connector is online. +3. Make sure that there are no dialogue boxes open in QuickBooks that are interfering with attempts to sync or export. To resolve this, close any open windows in QuickBooks Desktop so that you only see a gray screen, then try exporting or syncing again. +4. Check that you have the correct permissions. +5. Log in to QuickBooks Desktop as an Admin (in single-user mode). +6. Go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**. +7. Select the Web Connector and click **Properties**. +8. Make sure that the "Allow this application to login automatically" checkbox is selected and click **OK**. +9. Close all windows in QuickBooks. + +If these general troubleshooting steps don’t work, reach out to Concierge and have the following information ready to provide: + +1. What version of QuickBooks Desktop do you have (Enterprise 2016, Pro 2014, etc.)? +2. Is your QuickBooks program installed on your computer or a remote network/drive? +3. Is your QuickBooks company file installed on your computer or a remote network/drive? +4. Is your Web Connector installed on your computer or a remote network/drive? +5. If any of the above are on a remote option, is there a company that runs that remote environment? If so, who (ie: RightNetworks, SwissNet, Cloud9, etc.)? + +# Import issue or missing categories and/or tags + +Generally, if you are having issues importing data from QuickBooks to Expensify, this indicates that the integration needs to be updated or your version of QuickBooks may not support a specific configuration. + +## How to resolve + +1. Re-sync the connection between Expensify and QuickBooks Desktop. A fresh sync can often resolve any issues, especially if you have recently updated your chart of accounts or projects, customers, or jobs in QuickBooks Desktop. +2. Check your configuration in QuickBooks Desktop. Expensify will import the chart of accounts to be utilized either as categories or export account options, while projects, customers, and tags will be imported as tags. + +If these general troubleshooting steps don’t work, reach out to Concierge with context on what is specifically missing in Expensify, as well as screenshots from your QuickBooks Desktop setup. + +# Export or "can't find category/class/location/account" issue + +Generally, when an export error occurs, we’ll share the reason in the Report Comments section at the bottom of the report. This will give you an indication of how to resolve the error. + +## How to resolve + +1. Re-sync the connection between Expensify and QuickBooks Desktop. A fresh sync can often resolve any issues, especially if you have recently updated your chart of accounts or projects, customers, or jobs in QuickBooks Desktop. +2. Re-apply coding to expenses and re-export the report. If you’ve recently synced Expensify and QuickBooks or recently made changes to your Workspace category or tags settings, you may need to re-apply coding to expenses. +3. Make sure that your current version of QuickBooks Desktop supports the selected export option. Different versions of QuickBooks Desktop support different export options and the [version that you own](https://quickbooks.intuit.com/desktop/) may not be compatible with the export type. + +If these general troubleshooting steps don’t work, reach out to Concierge with the Report ID, some context on what you’re trying to do, and a screenshot of the Expensify error message. + +# “Oops!” error when syncing or exporting + +Generally, an “Oops!” error can often be temporary or a false error. Although you will see a message pop up, there may actually not be an actual issue. + +## How to resolve + +1. Check to see if the sync or export was successful. +2. If it wasn't, please attempt to sync or export the connection again. + +If the problem persists, download the QuickBooks Desktop log file via the Web Connector (click View Logs to download them) and reach out to Concierge for further assistance. + +{% include info.html %} +If you’re using a remote server (e.g. RightNetworks), you may need to contact that support team to request your logs. +{% include end-info.html %} diff --git a/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md b/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md new file mode 100644 index 000000000000..922bf9d07056 --- /dev/null +++ b/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md @@ -0,0 +1,172 @@ +--- +title: Expensify Card Perks +description: An overview of all the various perks the Expensify Card offers +--- +## Expensify-specific Perks + +### Cashback +Get 1% cash back with every swipe — no minimums necessary — and 2% back if you spend $250k+/month across cards. + +This applies to USD purchases only. + +### Discounts on Monthly Expensify Bill +Get the Expensify Visa® Commercial Card and use it for at least half of your organization's monthly expenses to save 50% on your monthly Expensify bill. + +## Partner-specific Perks + +### Amazon AWS +Whether you're a two-person startup or a venture-backed company, AWS Activate provides access to the resources you need to get started on AWS quickly, including free credits, technical support, and training. All Expensify Cardholders qualify when they add their Expensify Card for AWS billing! + +**How to redeem:** Apply [here](https://aws.amazon.com/activate/portfolio-signup) using OrgID: 0qyIA (Case Sensitive). + +For more details, refer to the [AWS Activate terms and conditions](https://aws.amazon.com/activate/terms/) and the [Activate FAQs](https://aws.amazon.com/activate/faq/). + +### Stripe +Stripe’s integrated payments platform helps you build and scale your business globally, whether you're creating a subscription service, an on-demand marketplace, or an e-commerce store. + +Stripe will waive the processing fees for the first $5,000 in payments for Expensify Cardholders. + +**How to redeem:** Sign up for Stripe using your Expensify Card. + +### Lamar Advertising +Lamar offers out-of-home advertising on billboards, digital displays, airport signage, transit, and highway logo signs. Expensify Cardholders receive a minimum 10% discount on their first campaign. + +**How to redeem:** Contact Expensify’s dedicated account manager, Lisa Kane (email: lkane@lamar.com), and mention that you’re an Expensify Cardholder. + +### Carta +Simplify equity management with Carta. Expensify Cardholders receive a 20% discount on the first year and waived implementation fees. + +**How to redeem:** Sign up using your Expensify Card. + +### Pilot +Pilot specializes in bookkeeping and tax preparation for startups and e-commerce providers. When you use Pilot, you're paired with a dedicated finance expert who handles the work for you and answers your questions. + +**Offer:** 20% off the first six months of Pilot Core. + +**How to redeem:** Sign up using your Expensify Card. + +### Spotlight Reporting +Spotlight Reporting is a cloud-based reporting and forecasting tool designed by accountants, for accountants. Expensify Cardholders receive a 20% discount on their subscription for the first six months, plus one free seat for Spotlight Certification. + +**How to redeem:** Sign up using your Expensify Card. + +### Guideline +Guideline's full-service 401(k) plans make it easier and more affordable to offer your employees the retirement benefits they deserve. + +**Offer:** Three months free. + +**How to redeem:** Sign up using your Expensify Card. + +### Gusto +Gusto's platform helps businesses onboard, pay, insure, and support their teams. Expensify Cardholders receive three months of free service. + +**How to redeem:** Sign up using your Expensify Card. + +### QuickBooks Online +QuickBooks accounting software keeps your books accurate and up to date with features like invoicing, cash flow management, expense tracking, and more. + +**Offer:** 30% off QuickBooks Online for the first 12 months. + +**How to redeem:** Sign up using your Expensify Card. + +### Highfive +Highfive improves the ease and quality of in-room video conferencing. Expensify Cardholders receive 50% off the Highfive Select Starter Package and 10% off the Highfive Premium Package. + +**How to redeem:** Sign up using your Expensify Card. + +### Zendesk +Expensify Cardholders receive $436 in credits for Zendesk Suite products per month for the first year. + +**How to redeem:** +- Reach out to startups@zendesk.com with the message: "Expensify asked me to send an email regarding the Zendesk promotion.” You'll receive a promo code to use. +- Start a Zendesk trial (Suite or another plan) in USD (if your trial is not in USD, contact Zendesk). +- Click the "Buy Now" button inside your trial. +- Select your plan with monthly billing. + - The $436 monthly credit applies to up to four licenses of the Suite but can also be applied to any other monthly plan. +- Enter the promo code you receive. +- Complete the checkout process. + - After 12 monthly billing periods, your free credit will expire, and you'll be charged for the next month. + +### Xero +Xero offers accounting software with everything you need to run your business seamlessly. + +**Offer:** U.S. residents receive 50% off Xero for six months. + +**How to redeem:** Visit [this page](https://apps.xero.com/us/app/expensify?xtid=x30expensify&utm_source=expensify&utm_medium=web&utm_campaign=cardoffer) and sign up using your Expensify Card. + +### Freshworks +Boost your startup journey with customer and employee engagement solutions from Freshworks, including CRM, live chat, support, marketing automation, ITSM, and HRMS. + +**Offer:** $4,000 in credits on Freshworks products. + +**How to redeem:** Click [here](https://www.freshworks.com/partners/startup-program/expensify-card/) and fill out the form; Freshworks will automatically recognize your company as an Expensify Card customer. + +### Slack +Get 25% off your first year with Slack, enjoying premium features like unlimited messaging, apps, Slack Connect channels, group video calls, priority support, and more. + +**How to redeem:** Click [here](https://slack.com/promo/partner?remote_promo=ead919f5) to redeem the offer using your Expensify Card. + +### Deel.com +Deel simplifies onboarding international team members in 150 different countries. Expensify Cardholders receive three months free, followed by 30% off for the rest of the year. + +**How to redeem:** Click [here](https://www.deel.com/partners/expensify) and sign up using your Expensify Card. + +### Snap +Expensify Cardholders receive $1,000 in Snap credits when they spend $1,000 in Snapchat's Ads Manager. + +**How to redeem:** +- Click "Create Ad" or "Request a Call" by clicking [here](https://forbusiness.snapchat.com/). +- Enter your details to set up your account if you don't already have one. +- Add the Expensify Card as your payment option for your Snap Business account. +- Credits will automatically be placed in your account once you've reached $1,000 in spend. + +### Aircall +Aircall is a cloud-based phone system for sales and support teams. Expensify Cardholders receive two months free, with discounts ranging from $270 to $9,000+ depending on the number of users. + +**How to redeem:** +- Click [here](http://pages.aircall.io/Expensify-RewardsPartnerReferral.html) to sign up for a demo. +- Let the Aircall team know you're an Expensify customer. + +### NetSuite +NetSuite helps companies manage core business processes with a cloud-based ERP and accounting software. Expensify has a direct integration with NetSuite to synchronize data and customize expense coding. + +**Offer:** 10% off for the first year. + +**How to redeem:** +- Fill out this [Google form](https://docs.google.com/forms/d/e/1FAIpQLSeiOzLrdO-MgqeEMwEqgdQoh4SJBi42MZME9ycHp4SQjlk3bQ/viewform?usp=sf_link). +- An Expensify rep will introduce you to a NetSuite sales rep to start the process. +- Once set up, pay for your first year with NetSuite, and Expensify will send you a payment equal to 10% of your first-year contract within three months of your first NetSuite invoice. + +**Note:** This offer is only for prospective NetSuite customers. + +### PagerDuty +PagerDuty's platform integrates machine data and human intelligence to improve visibility and agility across organizations. + +**Offer:** 25% off. + +**How to redeem:** Sign up using your Expensify Card and enter the discount code EXPENSIFYPDTEAM for the Team plan or EXPENSIFYPDBUSINESS for the Business plan at checkout. + +### Typeform +Typeform makes collecting and sharing information easy and conversational, allowing you to create anything from surveys to apps without writing a single line of code. + +**Offer:** 30% off annual Premium and Professional plans. + +**How to redeem:** +- Click [here](https://try.typeform.com/expensify/?utm_source=expensify&utm_medium=referral&utm_campaign=expensify_integration&utm_content=directory) to get Typeform. +- Enter your details and set up your free account. +- Verify your email by clicking on the link Typeform sends you. +- Complete the onboarding flow within Typeform. +- Click the "Upgrade" button in your workspace. +- Select your plan. +- Enter the coupon code EXPENSIFY30 on the checkout page. +- Fill out all payment details using your Expensify Card and click "Upgrade now." + +### Intercom +Intercom offers a suite of messaging-first products to help businesses accelerate growth across the customer lifecycle. + +**Offer:** Three months of free service. + +**How to redeem:** Sign up using your Expensify Card. + +### Talkspace +Talkspace provides prescription management and personalized treatment through a network of licensed prescribers trained in mental healthcare. Expensify Cardholders receive $125 off Talk diff --git a/docs/articles/expensify-classic/workspaces/Enable-per-diem-expenses.md b/docs/articles/expensify-classic/workspaces/Enable-per-diem-expenses.md index 3ab757e75e9a..2d2f1b5afddc 100644 --- a/docs/articles/expensify-classic/workspaces/Enable-per-diem-expenses.md +++ b/docs/articles/expensify-classic/workspaces/Enable-per-diem-expenses.md @@ -14,9 +14,9 @@ To enable and set per diem rates, 4. Click the **Per Diem** tab on the left. 5. Click the Per Diem toggle to enable it. 6. Create a .csv, .txt, .xls, or .xlsx spreadsheet containing four columns: Destination, Sub-rate, Amount, and Currency. You’ll want a different row for each location that an employee may travel to, which may include states and/or countries to help account for cost differences across various locations. Here are some example templates you can use: - - [Germany multi-subrates](https://community.expensify.com/home/leaving?allowTrusted=1&target=https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fconcierge-responses-expensify-com%2Fuploads%252F1596692482998-Germany%2B-%2BPer%2BDiem.csv) - - [Sweden multi-subrates](https://community.expensify.com/home/leaving?allowTrusted=1&target=https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fconcierge-responses-expensify-com%2Fuploads%252F1604410653223-Swedish%2BPer%2BDiem%2BRates.csv) - - [South Africa single rates](https://community.expensify.com/home/leaving?allowTrusted=1&target=https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fconcierge-responses-expensify-com%2Fuploads%252F1596692413995-SA%2BPer%2BDiem%2BRates.csv) + - [Germany rates]({{site.url}}/assets/Files/Germany-per-diem.csv) + - [Sweden rates]({{site.url}}/assets/Files/Sweden-per-diem.csv) + - [South Africa single rates]({{site.url}}/assets/Files/South-Africa-per-diem.csv) 7. Click **Import from spreadsheet**. 8. Click **Upload** to select your spreadsheet. diff --git a/docs/articles/new-expensify/connections/netsuite/Configure-Netsuite.md b/docs/articles/new-expensify/connections/netsuite/Configure-Netsuite.md index 7ae0aa577468..ca0dbfe9ae54 100644 --- a/docs/articles/new-expensify/connections/netsuite/Configure-Netsuite.md +++ b/docs/articles/new-expensify/connections/netsuite/Configure-Netsuite.md @@ -1,6 +1,252 @@ --- title: Configure Netsuite -description: Coming soon +description: Configure the Import, Export, and Advanced settings for Expensify's integration with NetSuite +order: 2 --- -# Coming soon +# Configure NetSuite integration +## Step 1: Configure import settings + +The following section will help you determine how data will be imported from NetSuite into Expensify. To change your import settings, navigate to the Accounting settings for your workspace, then click **Import** under the NetSuite connection. + +### Expense Categories +Your NetSuite Expense Categories are automatically imported into Expensify as categories. This cannot be amended, and any new categories you'd like to add must be added as Expense Categories in NetSuite. + +Once imported, you can turn specific Categories on or off under **Settings > Workspaces > [Workspace Name] > Categories**. + +### Departments, Classes, and Locations +The NetSuite integration allows you to import departments, classes, and locations from NetSuite into Expensify as Tags, Report Fields, or using the NetSuite Employee Default. + +- **NetSuite Employee Default:** If default Department, Class, and Locations have been configured on NetSuite employee records, then you can choose to have the NetSuite employee default applied upon export from Expensify to NetSuite. With this selection, employees will not make a selection in Expensify. +- **Tags:** Employees can select the department, class, or location on each individual expense. If the employee's NetSuite employee record has a default value, then each expense will be defaulted to that tag upon creation, with the option for the employee to select a different value on each expense. +- **Report Fields:** Employees can select one department/class/location for each expense report. + + +New departments, classes, and locations must be added in NetSuite. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. + +### Customers and Projects +The NetSuite integration allows you to import customers and projects into Expensify as Tags or Report Fields. + +- **Tags:** Employees can select the customer or project on each individual expense. +- **Report Fields:** Employees can select one department/class/location for each expense report. + +New customers and projects must be added in NetSuite. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. + +When importing customers or projects, you can also choose to enable **Cross-subsidiary customers/projects**. This setting allows you to import Customers and Projects across all NetSuite subsidiaries to a single Expensify workspace. This setting requires you to enable “Intercompany Time and Expense” in NetSuite. To enable that feature in NetSuite, go to **Setup > Company > Setup Tasks: Enable Features > Advanced Features**. + +### Tax +The NetSuite integration allows users to apply a tax rate and amount to each expense for non-US NetSuite subsidiaries. To do this, import Tax Groups from NetSuite: + +1. In NetSuite, head to **Setup > Accounting > Tax Groups** +2. Once imported, go to the NetSuite connection configuration page in Expensify (under **Settings > Workspaces > [Workspace Name] > Accounting > NetSuite > Import**) +3. Enable Tax +4. Go back to the Accounting screen, click the three dots next to NetSuite, and click **Sync now** +5. All Tax Groups for the connected NetSuite subsidiary will be imported to Expensify as taxes. +6. After syncing, go to **Settings > Workspace > [Workspace Name] > Tax** to see the tax groups imported from NetSuite + +### Custom Segments +You can import one or more Custom Segments from NetSuite for selection in Expensify. To add a Custom Segment to your Expensify workspace: + +1. Go to **Settings > Workspaces > [Workspace Name] > Accounting** +2. Click **Import** under NetSuite +3. Click **Custom segments/records** +4. Click **Add custom segment/record** + +From there, you'll walk through a simple setup wizard. You can find detailed instructions below for each setup step. + +1. In Step 1, you'll select whether you'd like to import a custom segment or a custom record. For a Custom Segment, continue. We have separate instructions for [Custom Records](link) and [Custom Lists](link). +2. **Segment Name** + a. Log into NetSuite as an administrator + b. Go to **Customization > Lists, Records, & Fields > Custom Segments** + c. You’ll see the Segment Name on the Custom Segments page +3. Internal ID + a. Ensure you have internal IDs enabled in NetSuite under **Home > Set Preferences** + b. Navigate back to the **Custom Segments** page + c. Click the **Custom Record Type** link + d. You’ll see the Internal ID on the Custom Record Type page +4. **Script ID/Field ID** + a. If configuring Custom Segments as Report Fields, use the Field ID on the Transactions tab (under **Custom Segments > Transactions**). If no Field ID is shown, use the unified ID (just called “ID” right below the “Label”). + b. If configuring Custom Segments as Tags, use the Field ID on the Transaction Columns tab (under **Custom Segments > Transaction Columns**). If no Field ID is shown, use the unified ID (just called “ID” right below the “Label”). + c. Note that as of 2019.1, any new custom segments that you create automatically use the unified ID, and the "Use as Field ID" box is not visible. If you are editing a custom segment definition that was created before 2019.1, the "Use as Field ID" box is available. To use a unified ID for the entire custom segment definition, check the "Use as Field ID" box. When the box is checked, no field ID fields or columns are shown on the Application & Sourcing subtabs because one ID is used for all fields. +5. Select whether you'd like to import the custom segment as Tags or Report Fields +6. Finally, confirm that all the details look correct + +**Note:** Don’t use the “Filtered by” feature available for Custom Segments. Expensify can’t make these dependent on other fields. If you do have a filter selected, we suggest switching that filter in NetSuite to “Subsidiary” and enabling all subsidiaries to ensure you don’t receive any errors upon exporting reports. + +### Custom Records +You can import one or more Custom Records from NetSuite for selection in Expensify. To add a Custom Record to your Expensify workspace: + +1. Go to **Settings > Workspaces > [Workspace Name] > Accounting** +2. Click **Import** under NetSuite +3. Click **Custom segments/records** +4. Click **Add custom segment/record** + +From there, you'll walk through a simple setup wizard. You can find detailed instructions below for each setup step. + +1. In Step 1, you'll select whether you'd like to import a custom segment or a custom record. For a Custom Record, continue. We have separate instructions for [Custom Segments](link) and [Custom Lists](link). +2. **Segment Name** + a. Log into NetSuite as an administrator + b. Go to **Customization > Lists, Records, & Fields > Custom Segments** + c. You’ll see the Custom Record Name on the Custom Segments page +3. **Internal ID** + a. Make sure you have Internal IDs enabled in NetSuite under **Home > Set Preferences** + b. Navigate back to the **Custom Segment** page + c. Click the **Custom Record Type** hyperlink + d. You’ll see the Internal ID on the Custom Record Type page +4. **Transaction Column ID** + a. If configuring Custom Records as Report Fields, use the Field ID on the Transactions tab (under **Custom Segments > Transactions**). + b. If configuring Custom Records as Tags, use the Field ID on the Transaction Columns tab (under **Custom Segments > Transaction Columns**). +5. Select whether you'd like to import the custom record as Tags or Report Fields +6. Finally, confirm that all the details look correct + +### Custom Lists +You can import one or more Custom Lists from NetSuite for selection in Expensify. To add a Custom List to your Expensify workspace: + +1. Go to **Settings > Workspaces > [Workspace Name] > Accounting** +2. Click **Import** under NetSuite +3. Click **Custom list** +4. Click **Add custom list** + +From there, you'll walk through a simple setup wizard. You can find detailed instructions below for each setup step. + +1. In Step 1, you'll select which Custom List you'd like to import from a pre-populated list +2. **Transaction Line Field ID** + a. Log into NetSuite as an admin + b. Search **“Transaction Line Fields”** in the global search + c. Click into the desired Custom List + d. You'll find the transaction Line Field ID along the left-hand side of the page +3. Select whether you'd like to import the custom list as Tags or Report Fields +4. Finally, confirm that all the details look correct + +From there, you should see the values for the Custom Lists under the Tag or Report Field settings in Expensify. +## Step 2: Configure export settings +There are numerous options for exporting data from Expensify to NetSuite. To access these settings, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Export** under NetSuite. + +### Preferred Exporter +Any workspace admin can export reports to NetSuite. For auto-export, Concierge will export on behalf of the preferred exporter. The preferred exporter will also be notified of any expense reports that fail to export to NetSuite due to an error. + +### Date +You can choose which date to use for the records created in NetSuite. There are three date options: + +1. **Date of last expense:** This will use the date of the previous expense on the report +2. **Submitted date:** The date the employee submitted the report +3. **Exported date:** The date you export the report to NetSuite + +### Export out-of-pocket expenses as +**Expense Reports** +Out-of-pocket expenses will be exported to NetSuite as expense reports, which will be posted to the payables account designated in NetSuite. + +**Vendor Bills** +Out-of-pocket expenses will be exported to NetSuite as vendor bills. Each report will be posted as payable to the vendor associated with the employee who submitted the report. You can also set an approval level in NetSuite for vendor bills. + +**Journal Entries** +Out-of-pocket expenses will be exported to NetSuite as journal entries. All the transactions will be posted to the payable account specified in the workspace. You can also set an approval level in NetSuite for the journal entries. + +Note: By default, journal entry forms do not contain a customer column, so it is not possible to export customers or projects with this export option. Also, The credit line and header level classifications are pulled from the employee record. + +### Export company card expenses as +**Expense Reports** +To export company card expenses as expense reports, you will need to configure your default corporate cards in NetSuite. To do this, you must select the correct card on the NetSuite employee records (for individual accounts) or the subsidiary record (If you use a non-One World account, the default is found in your accounting preferences). + +To update your expense report transaction form in NetSuite: + +1. Go to **Customization > Forms > Transaction Forms** +2. Click **Edit** next to the preferred expense report form +3. Go to the **Screen Fields > Main** tab +4. Check “Show” for "Account for Corporate Card Expenses" +5. Go to the **Screen Fields > Expenses** tab +6. Check “Show” for "Corporate Card" + +You can also select the default account on your employee record to use individual corporate cards for each employee. Make sure you add this field to your employee entity form in NetSuite. If you have multiple cards assigned to a single employee, you cannot export to each account. You can only have a single default per employee record. + +**Vendor Bills** +Company card expenses will be posted as a vendor bill payable to the default vendor specified in your workspace Accounting settings. You can also set an approval level in NetSuite for the bills. + + +**Journal Entries** +Company Card expenses will be posted to the Journal Entries posting account selected in your workspace Accounting settings. + +Important Notes: + +- Expensify Card expenses will always export as Journal Entries, even if you have Expense Reports or Vendor Bills configured for non-reimbursable expenses on the Export tab +- Journal entry forms do not contain a customer column, so it is not possible to export customers or projects with this export option +- The credit line and header level classifications are pulled from the employee record + +### Export invoices to +Select the Accounts Receivable account where you want your Invoice reports to export. In NetSuite, the invoices are linked to the customer, corresponding to the email address where the invoice was sent. + +### Export foreign currency amount +Enabling this feature allows you to send the original amount of the expense rather than the converted total when exporting to NetSuite. This option is only available when exporting out-of-pocket expenses as Expense Reports. + +### Export to next open period +When this feature is enabled and you try exporting an expense report to a closed NetSuite period, we will automatically export to the next open period instead of returning an error. + + +## Step 3: Configure advanced settings +To access the advanced settings of the NetSuite integration, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Advanced** under NetSuite. + + +Let’s review the different advanced settings and how they interact with the integration. + +### Auto-sync +We strongly recommend enabling auto-sync to ensure that the information in NetSuite and Expensify is always in sync. The following will occur when auto-sync is enabled: + +**Daily sync from NetSuite to Expensify:** Once a day, Expensify will sync any changes from NetSuite into Expensify. This includes any new, updated, or removed departments/classes/locations/projects/etc. + +**Auto-export:** When an expense report reaches its final state in Expensify, it will be automatically exported to NetSuite. The final state will either be reimbursement (if you reimburse members through Expensify) or final approval (if you reimburse members outside of Expensify). + +**Reimbursement-sync:** If Sync Reimbursed Reports (more details below) is enabled, then we will sync the reimbursement status of reports between Expensify and NetSuite. + +### Sync reimbursed reports +When Sync reimbursed reports is enabled, the reimbursement status will be synced between Expensify and NetSuite. + +**If you reimburse members through Expensify:** Reimbursing an expense report will trigger auto-export to NetSuite. When the expense report is exported to NetSuite, a corresponding bill payment will also be created in NetSuite. + +**If you reimburse members outside of Expensify:** Expense reports will be exported to NetSuite at time of final approval. After you mark the report as paid in NetSuite, the reimbursed status will be synced back to Expensify the next time the integration syncs. + +To ensure this feature works properly for expense reports, make sure that the reimbursement account you choose within the settings matches the default account for Bill Payments in NetSuite. When exporting invoices, once marked as Paid, the payment is marked against the account selected after enabling the Collection Account setting. + +### Invite employees and set approvals +Enabling this feature will invite all employees from the connected NetSuite subsidiary to your Expensify workspace. Once imported, Expensify will send them an email letting them know they’ve been added to a workspace. + +In addition to inviting employees, this feature enables a custom set of approval workflow options, which you can manage in Expensify Classic: + +- **Basic Approval:** A single level of approval, where all users submit directly to a Final Approver. The Final Approver defaults to the workspace owner but can be edited on the people page. +- **Manager Approval (default):** Two levels of approval route reports first to an employee’s NetSuite expense approver or supervisor, and second to a workspace-wide Final Approver. By NetSuite convention, Expensify will map to the supervisor if no expense approver exists. The Final Approver defaults to the workspace owner but can be edited on the people page. +- **Configure Manually:** Employees will be imported, but all levels of approval must be manually configured on the workspace’s People settings page. If you enable this setting, it’s recommended you review the newly imported employees and managers on the **Settings > Workspaces > Group > [Workspace Name] > People** page. + +### Auto-create employees/vendors +With this feature enabled, Expensify will automatically create a new employee or vendor in NetSuite (if one doesn’t already exist) using the name and email of the report submitter. + +### Enable newly imported categories +With this feature enabled, anytime a new Expense Category is created in NetSuite, it will be imported into Expensify as an enabled category. If the feature is disabled, then new Expense Categories will be imported into Expensify as disabled. + +### Setting approval levels +You can set the NetSuite approval level for each different export type: + +- **Expense report approval level:** Choose from "NetSuite default preference," “Only supervisor approved,” “Only accounting approved,” or “Supervisor and accounting approved.” +- **Vendor bill approval level and Journal entry approval level:** Choose from "NetSuite default preference," “Pending approval,” or “Approved for posting.” + +If you have Approval Routing selected in your accounting preference, this will override the selections in Expensify. If you do not wish to use Approval Routing in NetSuite, go to **Setup > Accounting > Accounting Preferences > Approval Routing** and ensure Vendor Bills and Journal Entries are not selected. + +### Custom form ID +By default, Expensify will create entries using the preferred transaction form set in NetSuite. Alternatively, you have the option to designate a specific transaction form to be used. + + + +## FAQ + +### How does Auto-sync work with reimbursed reports? +If a report is reimbursed via ACH or marked as reimbursed in Expensify and then exported to NetSuite, the report is automatically marked as paid in NetSuite. + +If a report is exported to NetSuite, then marked as paid in NetSuite, the report will automatically be marked as reimbursed in Expensify during the next sync. + +### Will enabling auto-sync affect existing approved and reimbursed reports? +Auto-sync will only export newly approved reports to NetSuite. Any reports that were approved or reimbursed before enabling auto-sync will need to be manually exported in order to sync them to NetSuite. + + +### When using multi-currency features in NetSuite, can expenses be exported with any currency? +When using multi-currency features with NetSuite, remember these points: + +**Employee/Vendor currency:** The currency set for a NetSuite vendor or employee record must match the subsidiary currency for whichever subsidiary you export that user's reports to. A currency mismatch will cause export errors. +**Bank Account Currency:** When synchronizing bill payments, your bank account’s currency must match the subsidiary’s currency. Failure to do so will result in an “Invalid Account” error. diff --git a/docs/articles/new-expensify/connections/netsuite/Connect-to-NetSuite.md b/docs/articles/new-expensify/connections/netsuite/Connect-to-NetSuite.md index 7cf70cca5abc..19009c016862 100644 --- a/docs/articles/new-expensify/connections/netsuite/Connect-to-NetSuite.md +++ b/docs/articles/new-expensify/connections/netsuite/Connect-to-NetSuite.md @@ -125,251 +125,3 @@ You need a Control workspace to integrate with NetSuite. If you have a Collect w ### Page size Make sure your page size is set to 1000 in NetSuite for importing your customers and vendors. Go to **Setup > Integration > Web Services Preferences** and search **Page Size** to determine your page size. - - -# Configure NetSuite integration -## Step 1: Configure import settings - -The following section will help you determine how data will be imported from NetSuite into Expensify. To change your import settings, navigate to the Accounting settings for your workspace, then click **Import** under the NetSuite connection. - -### Expense Categories -Your NetSuite Expense Categories are automatically imported into Expensify as categories. This cannot be amended, and any new categories you'd like to add must be added as Expense Categories in NetSuite. - -Once imported, you can turn specific Categories on or off under **Settings > Workspaces > [Workspace Name] > Categories**. - -### Departments, Classes, and Locations -The NetSuite integration allows you to import departments, classes, and locations from NetSuite into Expensify as Tags, Report Fields, or using the NetSuite Employee Default. - -- **NetSuite Employee Default:** If default Department, Class, and Locations have been configured on NetSuite employee records, then you can choose to have the NetSuite employee default applied upon export from Expensify to NetSuite. With this selection, employees will not make a selection in Expensify. -- **Tags:** Employees can select the department, class, or location on each individual expense. If the employee's NetSuite employee record has a default value, then each expense will be defaulted to that tag upon creation, with the option for the employee to select a different value on each expense. -- **Report Fields:** Employees can select one department/class/location for each expense report. - - -New departments, classes, and locations must be added in NetSuite. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. - -### Customers and Projects -The NetSuite integration allows you to import customers and projects into Expensify as Tags or Report Fields. - -- **Tags:** Employees can select the customer or project on each individual expense. -- **Report Fields:** Employees can select one department/class/location for each expense report. - -New customers and projects must be added in NetSuite. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. - -When importing customers or projects, you can also choose to enable **Cross-subsidiary customers/projects**. This setting allows you to import Customers and Projects across all NetSuite subsidiaries to a single Expensify workspace. This setting requires you to enable “Intercompany Time and Expense” in NetSuite. To enable that feature in NetSuite, go to **Setup > Company > Setup Tasks: Enable Features > Advanced Features**. - -### Tax -The NetSuite integration allows users to apply a tax rate and amount to each expense for non-US NetSuite subsidiaries. To do this, import Tax Groups from NetSuite: - -1. In NetSuite, head to **Setup > Accounting > Tax Groups** -2. Once imported, go to the NetSuite connection configuration page in Expensify (under **Settings > Workspaces > [Workspace Name] > Accounting > NetSuite > Import**) -3. Enable Tax -4. Go back to the Accounting screen, click the three dots next to NetSuite, and click **Sync now** -5. All Tax Groups for the connected NetSuite subsidiary will be imported to Expensify as taxes. -6. After syncing, go to **Settings > Workspace > [Workspace Name] > Tax** to see the tax groups imported from NetSuite - -### Custom Segments -You can import one or more Custom Segments from NetSuite for selection in Expensify. To add a Custom Segment to your Expensify workspace: - -1. Go to **Settings > Workspaces > [Workspace Name] > Accounting** -2. Click **Import** under NetSuite -3. Click **Custom segments/records** -4. Click **Add custom segment/record** - -From there, you'll walk through a simple setup wizard. You can find detailed instructions below for each setup step. - -1. In Step 1, you'll select whether you'd like to import a custom segment or a custom record. For a Custom Segment, continue. We have separate instructions for [Custom Records](link) and [Custom Lists](link). -2. **Segment Name** - a. Log into NetSuite as an administrator - b. Go to **Customization > Lists, Records, & Fields > Custom Segments** - c. You’ll see the Segment Name on the Custom Segments page -3. Internal ID - a. Ensure you have internal IDs enabled in NetSuite under **Home > Set Preferences** - b. Navigate back to the **Custom Segments** page - c. Click the **Custom Record Type** link - d. You’ll see the Internal ID on the Custom Record Type page -4. **Script ID/Field ID** - a. If configuring Custom Segments as Report Fields, use the Field ID on the Transactions tab (under **Custom Segments > Transactions**). If no Field ID is shown, use the unified ID (just called “ID” right below the “Label”). - b. If configuring Custom Segments as Tags, use the Field ID on the Transaction Columns tab (under **Custom Segments > Transaction Columns**). If no Field ID is shown, use the unified ID (just called “ID” right below the “Label”). - c. Note that as of 2019.1, any new custom segments that you create automatically use the unified ID, and the "Use as Field ID" box is not visible. If you are editing a custom segment definition that was created before 2019.1, the "Use as Field ID" box is available. To use a unified ID for the entire custom segment definition, check the "Use as Field ID" box. When the box is checked, no field ID fields or columns are shown on the Application & Sourcing subtabs because one ID is used for all fields. -5. Select whether you'd like to import the custom segment as Tags or Report Fields -6. Finally, confirm that all the details look correct - -**Note:** Don’t use the “Filtered by” feature available for Custom Segments. Expensify can’t make these dependent on other fields. If you do have a filter selected, we suggest switching that filter in NetSuite to “Subsidiary” and enabling all subsidiaries to ensure you don’t receive any errors upon exporting reports. - -### Custom Records -You can import one or more Custom Records from NetSuite for selection in Expensify. To add a Custom Record to your Expensify workspace: - -1. Go to **Settings > Workspaces > [Workspace Name] > Accounting** -2. Click **Import** under NetSuite -3. Click **Custom segments/records** -4. Click **Add custom segment/record** - -From there, you'll walk through a simple setup wizard. You can find detailed instructions below for each setup step. - -1. In Step 1, you'll select whether you'd like to import a custom segment or a custom record. For a Custom Record, continue. We have separate instructions for [Custom Segments](link) and [Custom Lists](link). -2. **Segment Name** - a. Log into NetSuite as an administrator - b. Go to **Customization > Lists, Records, & Fields > Custom Segments** - c. You’ll see the Custom Record Name on the Custom Segments page -3. **Internal ID** - a. Make sure you have Internal IDs enabled in NetSuite under **Home > Set Preferences** - b. Navigate back to the **Custom Segment** page - c. Click the **Custom Record Type** hyperlink - d. You’ll see the Internal ID on the Custom Record Type page -4. **Transaction Column ID** - a. If configuring Custom Records as Report Fields, use the Field ID on the Transactions tab (under **Custom Segments > Transactions**). - b. If configuring Custom Records as Tags, use the Field ID on the Transaction Columns tab (under **Custom Segments > Transaction Columns**). -5. Select whether you'd like to import the custom record as Tags or Report Fields -6. Finally, confirm that all the details look correct - -### Custom Lists -You can import one or more Custom Lists from NetSuite for selection in Expensify. To add a Custom List to your Expensify workspace: - -1. Go to **Settings > Workspaces > [Workspace Name] > Accounting** -2. Click **Import** under NetSuite -3. Click **Custom list** -4. Click **Add custom list** - -From there, you'll walk through a simple setup wizard. You can find detailed instructions below for each setup step. - -1. In Step 1, you'll select which Custom List you'd like to import from a pre-populated list -2. **Transaction Line Field ID** - a. Log into NetSuite as an admin - b. Search **“Transaction Line Fields”** in the global search - c. Click into the desired Custom List - d. You'll find the transaction Line Field ID along the left-hand side of the page -3. Select whether you'd like to import the custom list as Tags or Report Fields -4. Finally, confirm that all the details look correct - -From there, you should see the values for the Custom Lists under the Tag or Report Field settings in Expensify. -## Step 2: Configure export settings -There are numerous options for exporting data from Expensify to NetSuite. To access these settings, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Export** under NetSuite. - -### Preferred Exporter -Any workspace admin can export reports to NetSuite. For auto-export, Concierge will export on behalf of the preferred exporter. The preferred exporter will also be notified of any expense reports that fail to export to NetSuite due to an error. - -### Date -You can choose which date to use for the records created in NetSuite. There are three date options: - -1. **Date of last expense:** This will use the date of the previous expense on the report -2. **Submitted date:** The date the employee submitted the report -3. **Exported date:** The date you export the report to NetSuite - -### Export out-of-pocket expenses as -**Expense Reports** -Out-of-pocket expenses will be exported to NetSuite as expense reports, which will be posted to the payables account designated in NetSuite. - -**Vendor Bills** -Out-of-pocket expenses will be exported to NetSuite as vendor bills. Each report will be posted as payable to the vendor associated with the employee who submitted the report. You can also set an approval level in NetSuite for vendor bills. - -**Journal Entries** -Out-of-pocket expenses will be exported to NetSuite as journal entries. All the transactions will be posted to the payable account specified in the workspace. You can also set an approval level in NetSuite for the journal entries. - -Note: By default, journal entry forms do not contain a customer column, so it is not possible to export customers or projects with this export option. Also, The credit line and header level classifications are pulled from the employee record. - -### Export company card expenses as -**Expense Reports** -To export company card expenses as expense reports, you will need to configure your default corporate cards in NetSuite. To do this, you must select the correct card on the NetSuite employee records (for individual accounts) or the subsidiary record (If you use a non-One World account, the default is found in your accounting preferences). - -To update your expense report transaction form in NetSuite: - -1. Go to **Customization > Forms > Transaction Forms** -2. Click **Edit** next to the preferred expense report form -3. Go to the **Screen Fields > Main** tab -4. Check “Show” for "Account for Corporate Card Expenses" -5. Go to the **Screen Fields > Expenses** tab -6. Check “Show” for "Corporate Card" - -You can also select the default account on your employee record to use individual corporate cards for each employee. Make sure you add this field to your employee entity form in NetSuite. If you have multiple cards assigned to a single employee, you cannot export to each account. You can only have a single default per employee record. - -**Vendor Bills** -Company card expenses will be posted as a vendor bill payable to the default vendor specified in your workspace Accounting settings. You can also set an approval level in NetSuite for the bills. - - -**Journal Entries** -Company Card expenses will be posted to the Journal Entries posting account selected in your workspace Accounting settings. - -Important Notes: - -- Expensify Card expenses will always export as Journal Entries, even if you have Expense Reports or Vendor Bills configured for non-reimbursable expenses on the Export tab -- Journal entry forms do not contain a customer column, so it is not possible to export customers or projects with this export option -- The credit line and header level classifications are pulled from the employee record - -### Export invoices to -Select the Accounts Receivable account where you want your Invoice reports to export. In NetSuite, the invoices are linked to the customer, corresponding to the email address where the invoice was sent. - -### Export foreign currency amount -Enabling this feature allows you to send the original amount of the expense rather than the converted total when exporting to NetSuite. This option is only available when exporting out-of-pocket expenses as Expense Reports. - -### Export to next open period -When this feature is enabled and you try exporting an expense report to a closed NetSuite period, we will automatically export to the next open period instead of returning an error. - - -## Step 3: Configure advanced settings -To access the advanced settings of the NetSuite integration, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Advanced** under NetSuite. - - -Let’s review the different advanced settings and how they interact with the integration. - -### Auto-sync -We strongly recommend enabling auto-sync to ensure that the information in NetSuite and Expensify is always in sync. The following will occur when auto-sync is enabled: - -**Daily sync from NetSuite to Expensify:** Once a day, Expensify will sync any changes from NetSuite into Expensify. This includes any new, updated, or removed departments/classes/locations/projects/etc. - -**Auto-export:** When an expense report reaches its final state in Expensify, it will be automatically exported to NetSuite. The final state will either be reimbursement (if you reimburse members through Expensify) or final approval (if you reimburse members outside of Expensify). - -**Reimbursement-sync:** If Sync Reimbursed Reports (more details below) is enabled, then we will sync the reimbursement status of reports between Expensify and NetSuite. - -### Sync reimbursed reports -When Sync reimbursed reports is enabled, the reimbursement status will be synced between Expensify and NetSuite. - -**If you reimburse members through Expensify:** Reimbursing an expense report will trigger auto-export to NetSuite. When the expense report is exported to NetSuite, a corresponding bill payment will also be created in NetSuite. - -**If you reimburse members outside of Expensify:** Expense reports will be exported to NetSuite at time of final approval. After you mark the report as paid in NetSuite, the reimbursed status will be synced back to Expensify the next time the integration syncs. - -To ensure this feature works properly for expense reports, make sure that the reimbursement account you choose within the settings matches the default account for Bill Payments in NetSuite. When exporting invoices, once marked as Paid, the payment is marked against the account selected after enabling the Collection Account setting. - -### Invite employees and set approvals -Enabling this feature will invite all employees from the connected NetSuite subsidiary to your Expensify workspace. Once imported, Expensify will send them an email letting them know they’ve been added to a workspace. - -In addition to inviting employees, this feature enables a custom set of approval workflow options, which you can manage in Expensify Classic: - -- **Basic Approval:** A single level of approval, where all users submit directly to a Final Approver. The Final Approver defaults to the workspace owner but can be edited on the people page. -- **Manager Approval (default):** Two levels of approval route reports first to an employee’s NetSuite expense approver or supervisor, and second to a workspace-wide Final Approver. By NetSuite convention, Expensify will map to the supervisor if no expense approver exists. The Final Approver defaults to the workspace owner but can be edited on the people page. -- **Configure Manually:** Employees will be imported, but all levels of approval must be manually configured on the workspace’s People settings page. If you enable this setting, it’s recommended you review the newly imported employees and managers on the **Settings > Workspaces > Group > [Workspace Name] > People** page. - -### Auto-create employees/vendors -With this feature enabled, Expensify will automatically create a new employee or vendor in NetSuite (if one doesn’t already exist) using the name and email of the report submitter. - -### Enable newly imported categories -With this feature enabled, anytime a new Expense Category is created in NetSuite, it will be imported into Expensify as an enabled category. If the feature is disabled, then new Expense Categories will be imported into Expensify as disabled. - -### Setting approval levels -You can set the NetSuite approval level for each different export type: - -- **Expense report approval level:** Choose from "NetSuite default preference," “Only supervisor approved,” “Only accounting approved,” or “Supervisor and accounting approved.” -- **Vendor bill approval level and Journal entry approval level:** Choose from "NetSuite default preference," “Pending approval,” or “Approved for posting.” - -If you have Approval Routing selected in your accounting preference, this will override the selections in Expensify. If you do not wish to use Approval Routing in NetSuite, go to **Setup > Accounting > Accounting Preferences > Approval Routing** and ensure Vendor Bills and Journal Entries are not selected. - -### Custom form ID -By default, Expensify will create entries using the preferred transaction form set in NetSuite. Alternatively, you have the option to designate a specific transaction form to be used. - - - -## FAQ - -### How does Auto-sync work with reimbursed reports? -If a report is reimbursed via ACH or marked as reimbursed in Expensify and then exported to NetSuite, the report is automatically marked as paid in NetSuite. - -If a report is exported to NetSuite, then marked as paid in NetSuite, the report will automatically be marked as reimbursed in Expensify during the next sync. - -### Will enabling auto-sync affect existing approved and reimbursed reports? -Auto-sync will only export newly approved reports to NetSuite. Any reports that were approved or reimbursed before enabling auto-sync will need to be manually exported in order to sync them to NetSuite. - - -### When using multi-currency features in NetSuite, can expenses be exported with any currency? -When using multi-currency features with NetSuite, remember these points: - -**Employee/Vendor currency:** The currency set for a NetSuite vendor or employee record must match the subsidiary currency for whichever subsidiary you export that user's reports to. A currency mismatch will cause export errors. -**Bank Account Currency:** When synchronizing bill payments, your bank account’s currency must match the subsidiary’s currency. Failure to do so will result in an “Invalid Account” error. diff --git a/docs/articles/new-expensify/connections/sage-intacct/Configure-Sage-Intacct.md b/docs/articles/new-expensify/connections/sage-intacct/Configure-Sage-Intacct.md index c5e549ff74d1..28cdc71ed80f 100644 --- a/docs/articles/new-expensify/connections/sage-intacct/Configure-Sage-Intacct.md +++ b/docs/articles/new-expensify/connections/sage-intacct/Configure-Sage-Intacct.md @@ -1,6 +1,133 @@ --- title: Configure Sage Intacct -description: Coming soon +description: Configure the Import, Export, and Advanced settings for Expensify's Sage Intacct integration +order: 3 --- -# Coming soon +# Configure Sage Intacct integration + +## Step 1: Select entity (multi-entity setups only) +If you have a multi-entity setup in Sage Intacct, you will be able to select in Expensify which Sage Intacct entity to connect each workspace to. Each Expensify workspace can either be connected to a single entity or connected at the Top Level. + +To select or change the Sage Intacct entity that your Expensify workspace is connected to, navigate to the Accounting settings for your workspace and click **Entity** under the Sage Intacct connection. + +## Step 2: Configure import settings +The following section will help you determine how data will be imported from Sage Intacct into Expensify. To change your import settings, navigate to the Accounting settings for your workspace, then click **Import** under the Sage Intacct connection. + +### Expense Types / Chart of Accounts +The categories in Expensify depend on how you choose to export out-of-pocket expenses: + +- If you choose to export out-of-pocket expenses as Expense Reports, your categories in Expensify will be imported from your Sage Intacct Expense Types +- If you choose to export out-of-pocket expenses as Vendor Bills, your categories will be imported directly from your Chart of Accounts (also known as GL Codes or Account Codes). + +You can disable unnecessary categories in Expensify by going to **Settings > Workspaces > [Workspace Name] > Categories**. Note that every expense must be coded with a Category, or it will fail to export. + +### Billable Expenses +Enabling billable expenses allows you to map your expense types or accounts to items in Sage Intacct. To do this, you’ll need to enable the correct permissions on your Sage Intacct user or role. This may vary based on the modules you use in Sage Intacct, so you should enable read-only permissions for relevant modules such as Projects, Purchasing, Inventory Control, and Order Entry. + +Once permissions are set, you can map categories to specific items, which will then export to Sage Intacct. When an expense is marked as Billable in Expensify, users must select the correct billable Category (Item), or there will be an error during export. + + +### Standard dimensions: Departments, Classes, and Locations +The Sage Intacct integration allows you to import standard dimensions into Expensify as tags, report fields, or using the Sage Intacct employee default. + +- **Sage Intacct Employee default:** This option is only available when exporting as expense reports. When this option is selected, nothing will be imported into Expensify - instead, the employee default will be applied to each expense upon export. +- **Tags:** Employees can select the department, class, or location on each individual expense. If the employee's Sage Intacct employee record has a default value, then each expense will default to that tag, with the option for the employee to select a different value on each expense. +- **Report Fields:** Employees can select one department/class/location for each expense report. + +New departments, classes, and locations must be added in Sage Intacct. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. + +Please note that when importing departments as tags, expense reports may show the tag name as "Tag" instead of "Department." + +### Customers and Projects +The Sage Intacct integration allows you to import customers and projects into Expensify as Tags or Report Fields. + +- **Tags:** Employees can select the customer or project on each individual expense. +- **Report Fields:** Employees can select one department/class/location for each expense report. + +New customers and projects must be added in Sage Intacct. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. + + +### Tax +The Sage Intacct integration supports native VAT and GST tax. To enable this feature, go to **Settings > Workspaces > [Workspace Name] > Accounting**, click **Import** under Sage Intacct, and enable Tax. Enabling this option will import your native tax rates from Sage Intacct into Expensify. From there, you can select default rates for each category under **Settings > Workspaces > [Workspace Name] > Categories**. + +For older Sage Intacct connections that don't show the Tax option, simply resync the connection by going to **Settings > Workspaces > [Workspace Name] > Accounting** and clicking the three dots next to Sage Intacct, and the tax toggle will appear. + +### User-Defined Dimensions +You can add User-Defined Dimensions (UDDs) to your workspace by locating the “Integration Name” in Sage Intacct. Please note that you must be logged in as an administrator in Sage Intacct to find the required fields. + +To find the Integration Name in Sage Intacct: + +1. Go to **Platform Services > Objects > List** +1. Set “filter by application” to “user-defined dimensions” +1. In Expensify, go to **Settings > Workspaces > [Workspace Name] > Accounting** and click **Import** under Sage Intacct +1. Enable User Defined Dimensions +1. Enter the “Integration name” and choose whether to import it into Expensify as expense-level tags or as report fields +1. Click **Save** + +Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. + + +## Step 5: Configure export settings +To access export settings, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Export** under Sage Intacct. + +### Preferred exporter +Any workspace admin can export reports to Sage Intacct. For auto-export, Concierge will export on behalf of the preferred exporter. The preferred exporter will also be notified of any expense reports that fail to export to Sage Intacct due to an error. + +### Export date +You can choose which date to use for the records created in Sage Intacct. There are three date options: + +1. **Date of last expense:** This will use the date of the previous expense on the report +1. **Export date:** The date you export the report to Sage Intacct +1. **Submitted date:** The date the employee submitted the report + +### Export out-of-pocket expenses as +Out-of-pocket expenses can be exported to Sage Intacct as **expense reports** or as **vendor bills**. If you choose to export as expense reports, you can optionally select a **default vendor**, which will apply to reimbursable expenses that don't have a matching vendor in Sage Intacct. + +### Export company card expenses as +Company Card expenses are exported separately from out-of-pocket expenses, and can be exported to Sage Intacct as credit card charges** or as **vendor bills**. + +- **Credit card charges:** When exporting as credit card charges, you must select a credit card account. You can optionally select a default vendor, which will apply to company card expenses that don't have a matching vendor in Sage Intacct. + - Credit card charges cannot be exported to Sage Intacct at the top-level if you have multi-currency enabled, so you will need to select an individual entity if you have this setup. +- **Vendor bills:** When exporting as vendor bills, you can select a default vendor, which will apply to company card expenses that don't have a matching vendor in Sage Intacct. + +If you centrally manage your company cards through Domains in Expensify Classic, you can export expenses from each individual card to a specific account in Sage Intacct in the Expensify Company Card settings. + +### 6. Configure advanced settings +To access the advanced settings of the Sage Intacct integration, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Advanced** under Sage Intacct. + + +Let’s review the different advanced settings and how they interact with the integration. + +### Auto-sync +We strongly recommend enabling auto-sync to ensure that the information in Sage Intacct and Expensify is always in sync. The following will occur when auto-sync is enabled: + +**Daily sync from Sage Intacct to Expensify:** Once a day, Expensify will sync any changes from Sage Intacct into Expensify. This includes any changes or additions to your Sage Intacct dimensions. + +**Auto-export:** When an expense report reaches its final state in Expensify, it will be automatically exported to Sage Intacct. The final state will either be reimbursement (if you reimburse members through Expensify) or final approval (if you reimburse members outside of Expensify). + +**Reimbursement-sync:** If Sync Reimbursed Reports (more details below) is enabled, then we will sync the reimbursement status of reports between Expensify and Sage Intacct. + +### Invite employees +Enabling this feature will invite all employees from the connected Sage Intacct entity to your Expensify workspace. Once imported, each employee who has not already been invited to that Expensify workspace will receive an email letting them know they’ve been added to the workspace. + +In addition to inviting employees, this feature enables a custom set of approval workflow options, which you can manage in Expensify Classic: + +- **Basic Approval:** A single level of approval, where all users submit directly to a Final Approver. The Final Approver defaults to the workspace owner but can be edited on the people page. +- **Manager Approval (default):** Each user submits to their manager, who is imported from Sage Intacct. You can optionally select a final approver who each manager forwards to for second-level approval. +- **Configure Manually:** Employees will be imported, but all levels of approval must be manually configured in Expensify. If you enable this setting, you can configure approvals by going to **Settings > Workspaces > [Workspace Name] > People**. + + +### Sync reimbursed reports +When Sync reimbursed reports is enabled, the reimbursement status will be synced between Expensify and Sage Intacct. + +**If you reimburse employees through Expensify:** Reimbursing an expense report will trigger auto-export to Sage Intacct. When the expense report is exported to Sage Intacct, a corresponding bill payment will also be created in Sage Intacct in the selected Cash and Cash Equivalents account. If you don't see the account you'd like to select in the dropdown list, please confirm that the account type is Cash and Cash Equivalents. + +**If you reimburse employees outside of Expensify:** Expense reports will be exported to Sage Intacct at time of final approval. After you mark the report as paid in Sage Intacct, the reimbursed status will be synced back to Expensify the next time the integration syncs. + +To ensure this feature works properly for expense reports, make sure that the account you choose within the settings matches the default account for Bill Payments in NetSuite. When exporting invoices, once marked as Paid, the payment is marked against the account selected after enabling the Collection Account setting. + +## FAQ + +### Will enabling auto-sync affect existing approved and reimbursed reports? +Auto-sync will only export newly approved reports to Sage Intacct. Any reports that were approved or reimbursed before enabling auto-sync will need to be manually exported in order to sync them to Sage Intacct. diff --git a/docs/articles/new-expensify/connections/sage-intacct/Connect-to-Sage-Intacct.md b/docs/articles/new-expensify/connections/sage-intacct/Connect-to-Sage-Intacct.md index cf04a3655b30..8e69a03fb666 100644 --- a/docs/articles/new-expensify/connections/sage-intacct/Connect-to-Sage-Intacct.md +++ b/docs/articles/new-expensify/connections/sage-intacct/Connect-to-Sage-Intacct.md @@ -187,138 +187,10 @@ If you use Platform Services: 1. Enter the credentials you set for your web services user in Step 1 1. Click **Confirm** - - -# Configure Sage Intacct integration - -## Step 1: Select entity (multi-entity setups only) -If you have a multi-entity setup in Sage Intacct, you will be able to select in Expensify which Sage Intacct entity to connect each workspace to. Each Expensify workspace can either be connected to a single entity or connected at the Top Level. - -To select or change the Sage Intacct entity that your Expensify workspace is connected to, navigate to the Accounting settings for your workspace and click **Entity** under the Sage Intacct connection. - -## Step 2: Configure import settings -The following section will help you determine how data will be imported from Sage Intacct into Expensify. To change your import settings, navigate to the Accounting settings for your workspace, then click **Import** under the Sage Intacct connection. - -### Expense Types / Chart of Accounts -The categories in Expensify depend on how you choose to export out-of-pocket expenses: - -- If you choose to export out-of-pocket expenses as Expense Reports, your categories in Expensify will be imported from your Sage Intacct Expense Types -- If you choose to export out-of-pocket expenses as Vendor Bills, your categories will be imported directly from your Chart of Accounts (also known as GL Codes or Account Codes). - -You can disable unnecessary categories in Expensify by going to **Settings > Workspaces > [Workspace Name] > Categories**. Note that every expense must be coded with a Category, or it will fail to export. - -### Billable Expenses -Enabling billable expenses allows you to map your expense types or accounts to items in Sage Intacct. To do this, you’ll need to enable the correct permissions on your Sage Intacct user or role. This may vary based on the modules you use in Sage Intacct, so you should enable read-only permissions for relevant modules such as Projects, Purchasing, Inventory Control, and Order Entry. - -Once permissions are set, you can map categories to specific items, which will then export to Sage Intacct. When an expense is marked as Billable in Expensify, users must select the correct billable Category (Item), or there will be an error during export. - - -### Standard dimensions: Departments, Classes, and Locations -The Sage Intacct integration allows you to import standard dimensions into Expensify as tags, report fields, or using the Sage Intacct employee default. - -- **Sage Intacct Employee default:** This option is only available when exporting as expense reports. When this option is selected, nothing will be imported into Expensify - instead, the employee default will be applied to each expense upon export. -- **Tags:** Employees can select the department, class, or location on each individual expense. If the employee's Sage Intacct employee record has a default value, then each expense will default to that tag, with the option for the employee to select a different value on each expense. -- **Report Fields:** Employees can select one department/class/location for each expense report. - -New departments, classes, and locations must be added in Sage Intacct. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. - -Please note that when importing departments as tags, expense reports may show the tag name as "Tag" instead of "Department." - -### Customers and Projects -The Sage Intacct integration allows you to import customers and projects into Expensify as Tags or Report Fields. - -- **Tags:** Employees can select the customer or project on each individual expense. -- **Report Fields:** Employees can select one department/class/location for each expense report. - -New customers and projects must be added in Sage Intacct. Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. - - -### Tax -The Sage Intacct integration supports native VAT and GST tax. To enable this feature, go to **Settings > Workspaces > [Workspace Name] > Accounting**, click **Import** under Sage Intacct, and enable Tax. Enabling this option will import your native tax rates from Sage Intacct into Expensify. From there, you can select default rates for each category under **Settings > Workspaces > [Workspace Name] > Categories**. - -For older Sage Intacct connections that don't show the Tax option, simply resync the connection by going to **Settings > Workspaces > [Workspace Name] > Accounting** and clicking the three dots next to Sage Intacct, and the tax toggle will appear. - -### User-Defined Dimensions -You can add User-Defined Dimensions (UDDs) to your workspace by locating the “Integration Name” in Sage Intacct. Please note that you must be logged in as an administrator in Sage Intacct to find the required fields. - -To find the Integration Name in Sage Intacct: - -1. Go to **Platform Services > Objects > List** -1. Set “filter by application” to “user-defined dimensions” -1. In Expensify, go to **Settings > Workspaces > [Workspace Name] > Accounting** and click **Import** under Sage Intacct -1. Enable User Defined Dimensions -1. Enter the “Integration name” and choose whether to import it into Expensify as expense-level tags or as report fields -1. Click **Save** - -Once imported, you can turn specific tags on or off under **Settings > Workspaces > [Workspace Name] > Tags**. You can turn specific report fields on or off under **Settings > Workspaces > [Workspace Name] > Report Fields**. - - -## Step 5: Configure export settings -To access export settings, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Export** under Sage Intacct. - -### Preferred exporter -Any workspace admin can export reports to Sage Intacct. For auto-export, Concierge will export on behalf of the preferred exporter. The preferred exporter will also be notified of any expense reports that fail to export to Sage Intacct due to an error. - -### Export date -You can choose which date to use for the records created in Sage Intacct. There are three date options: - -1. **Date of last expense:** This will use the date of the previous expense on the report -1. **Export date:** The date you export the report to Sage Intacct -1. **Submitted date:** The date the employee submitted the report - -### Export out-of-pocket expenses as -Out-of-pocket expenses can be exported to Sage Intacct as **expense reports** or as **vendor bills**. If you choose to export as expense reports, you can optionally select a **default vendor**, which will apply to reimbursable expenses that don't have a matching vendor in Sage Intacct. - -### Export company card expenses as -Company Card expenses are exported separately from out-of-pocket expenses, and can be exported to Sage Intacct as credit card charges** or as **vendor bills**. - -- **Credit card charges:** When exporting as credit card charges, you must select a credit card account. You can optionally select a default vendor, which will apply to company card expenses that don't have a matching vendor in Sage Intacct. - - Credit card charges cannot be exported to Sage Intacct at the top-level if you have multi-currency enabled, so you will need to select an individual entity if you have this setup. -- **Vendor bills:** When exporting as vendor bills, you can select a default vendor, which will apply to company card expenses that don't have a matching vendor in Sage Intacct. - -If you centrally manage your company cards through Domains in Expensify Classic, you can export expenses from each individual card to a specific account in Sage Intacct in the Expensify Company Card settings. - -### 6. Configure advanced settings -To access the advanced settings of the Sage Intacct integration, head to **Settings > Workspaces > [Workspace name] > Accounting** and click **Advanced** under Sage Intacct. - - -Let’s review the different advanced settings and how they interact with the integration. - -### Auto-sync -We strongly recommend enabling auto-sync to ensure that the information in Sage Intacct and Expensify is always in sync. The following will occur when auto-sync is enabled: - -**Daily sync from Sage Intacct to Expensify:** Once a day, Expensify will sync any changes from Sage Intacct into Expensify. This includes any changes or additions to your Sage Intacct dimensions. - -**Auto-export:** When an expense report reaches its final state in Expensify, it will be automatically exported to Sage Intacct. The final state will either be reimbursement (if you reimburse members through Expensify) or final approval (if you reimburse members outside of Expensify). - -**Reimbursement-sync:** If Sync Reimbursed Reports (more details below) is enabled, then we will sync the reimbursement status of reports between Expensify and Sage Intacct. - -### Invite employees -Enabling this feature will invite all employees from the connected Sage Intacct entity to your Expensify workspace. Once imported, each employee who has not already been invited to that Expensify workspace will receive an email letting them know they’ve been added to the workspace. - -In addition to inviting employees, this feature enables a custom set of approval workflow options, which you can manage in Expensify Classic: - -- **Basic Approval:** A single level of approval, where all users submit directly to a Final Approver. The Final Approver defaults to the workspace owner but can be edited on the people page. -- **Manager Approval (default):** Each user submits to their manager, who is imported from Sage Intacct. You can optionally select a final approver who each manager forwards to for second-level approval. -- **Configure Manually:** Employees will be imported, but all levels of approval must be manually configured in Expensify. If you enable this setting, you can configure approvals by going to **Settings > Workspaces > [Workspace Name] > People**. - - -### Sync reimbursed reports -When Sync reimbursed reports is enabled, the reimbursement status will be synced between Expensify and Sage Intacct. - -**If you reimburse employees through Expensify:** Reimbursing an expense report will trigger auto-export to Sage Intacct. When the expense report is exported to Sage Intacct, a corresponding bill payment will also be created in Sage Intacct in the selected Cash and Cash Equivalents account. If you don't see the account you'd like to select in the dropdown list, please confirm that the account type is Cash and Cash Equivalents. - -**If you reimburse employees outside of Expensify:** Expense reports will be exported to Sage Intacct at time of final approval. After you mark the report as paid in Sage Intacct, the reimbursed status will be synced back to Expensify the next time the integration syncs. - -To ensure this feature works properly for expense reports, make sure that the account you choose within the settings matches the default account for Bill Payments in NetSuite. When exporting invoices, once marked as Paid, the payment is marked against the account selected after enabling the Collection Account setting. ## FAQ ### Why wasn't my report automatically exported to Sage Intacct? There are a number of factors that can cause auto-export to fail. If this happens, you will find the specific export error in the report comments for the report that failed to export. Once you’ve resolved any errors, you can manually export the report to Sage Intacct. -### Will enabling auto-sync affect existing approved and reimbursed reports? -Auto-sync will only export newly approved reports to Sage Intacct. Any reports that were approved or reimbursed before enabling auto-sync will need to be manually exported in order to sync them to Sage Intacct. - - ### Can I export negative expenses to Sage Intacct? Yes, you can export negative expenses to Sage Intacct. If you are exporting out-of-pocket expenses as expense reports, then the total of each exported report cannot be negative. diff --git a/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting b/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting deleted file mode 100644 index 0c69493f3935..000000000000 --- a/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Xero Troubleshooting -description: A list of common Xero errors and how to resolve them ---- - -## Report won’t automatically export to Xero - -If an error occurs during an automatic export to Xero: - -- You’ll receive an email detailing the error. -- The error will appear in the related Workspace Chat, indicated by a red dot next to the report. -- For auto-sync errors, a message will be posted in the related #admins room. The message contains a link to the workspace’s accounting settings where an explanation for the error appears next to the connection. - -An error on a report will prevent it from automatically exporting. - -## How to resolve - -Open the expense and make the required changes. Then an admin must manually export the report to Xero by clicking the heading at the top of the expense and selecting Export. Then they’ll select Xero. - -![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_02.png){:width="100%"} - -![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_03.png){:width="100%"} - -## Unable to manually export a report - -To export a report, it must be in the Approved, Closed, or Reimbursed state. If it is in the Open state, clicking Export will lead to a notification that the data is not yet available for export. - -![Insert alt text for accessibility here]({{site.url}}/assets/images/Xero_help_04.png){:width="100%"} - -## How to resolve - -Open the report and make the required changes: - -- If the report is in the Open status, ensure that it is submitted. -- If the report is in the Processing status, an admin or approver will need to approve it. - -Once complete, an admin must manually export the report to Xero by clicking the heading at the top of the expense and selecting Export. Then they’ll select Xero. diff --git a/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md b/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md index 9c211efbaf24..f02541f5396f 100644 --- a/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md +++ b/docs/articles/new-expensify/connections/xero/Xero-Troubleshooting.md @@ -1,6 +1,37 @@ --- title: Xero Troubleshooting -description: Coming soon +description: More to Come Soon --- -# Coming soon +## Report won’t automatically export to Xero + +If an error occurs during an automatic export to Xero: + +- You'll receive an email detailing the error. +- The error will appear in the related Workspace Chat, indicated by a red dot next to the report. +- For auto-sync errors, a message will be posted in the related #admins room. The message contains a link to the workspace's accounting settings where an explanation for the error appears next to the connection. + +An error on a report will prevent it from automatically exporting. + +## How to resolve + +Open the expense and make the required changes. Then an admin must manually export the report to Xero by clicking the heading at the top of the expense and selecting Export. Then they'll select Xero. + +![App screenshot: Danny's Donuts owes $200, with export option highlighted]({{site.url}}/assets/images/Xero_help_02.png){:width="100%"} + +![App screenshot: Export options showing Xero integration and manual entry, with the Xero integration option highlighted]({{site.url}}/assets/images/Xero_help_03.png){:width="100%"} + +## Unable to manually export a report + +To export a report, it must be in the Approved, Closed, or Reimbursed state. If it is in the Open state, clicking Export will lead to a notification that the data is not yet available for export. + +![App screenshot: Export blocked due to draft or unpaid expenses]({{site.url}}/assets/images/Xero_help_04.png){:width="100%"} + +## How to resolve + +Open the report and make the required changes: + +- If the report is in the Open status, ensure that it is submitted. +- If the report is in the Processing status, an admin or approver will need to approve it. + +Once complete, an admin must manually export the report to Xero by clicking the heading at the top of the expense and selecting Export. Then they'll select Xero. diff --git a/docs/articles/new-expensify/expenses-&-payments/Approve-and-pay-expenses.md b/docs/articles/new-expensify/expenses-&-payments/Approve-and-pay-expenses.md index c037e8fe9cd3..5754d5f2ff90 100644 --- a/docs/articles/new-expensify/expenses-&-payments/Approve-and-pay-expenses.md +++ b/docs/articles/new-expensify/expenses-&-payments/Approve-and-pay-expenses.md @@ -4,18 +4,23 @@ description: Approve, hold, or pay expenses submitted to you ---
-When expenses are sent to you for approval, you have the option to: -- Approve and pay the expenses. -- Hold the expenses if payment needs to be delayed or if the expenses require additional information before they can be approved. +As a workspace admin, you can set an approval workflow for the expenses submitted to you. Expenses can be, + +- Instantly submitted without needing approval. +- Submitted at a desired frequency (daily, weekly, monthly) and follow an approval workflow. + +**Setting approval workflow and submission frequencies** + +# Manually approve expense + +When someone sends an expense or a group of expenses to you for approval, you’ll receive the expense in Expensify Chat for the related workspace. Chats with new updates appear with a green dot to the right of the chat message. Concierge also sends you an email notification for the new expense. {% include info.html %} -If your workspace does not require expense approvals, or if the expense is sent to you by a friend, you will not need to approve the expense and instead can immediately pay the expense when you are ready. +If an expense is sent to you by a friend, you will not need to approve the expense. Instead, you can immediately pay the expense when you are ready. {% include end-info.html %} # Approve expenses -When someone sends an expense or a group of expenses to you for approval, you’ll receive the expense in Expensify Chat for the related workspace. Chats with new updates appear with a green dot to the right of the chat message. Concierge also sends you an email notification for the new expense. - To approve an expense, 1. Open the Expensify Chat thread for the expense. @@ -27,7 +32,7 @@ To approve an expense, - **Request changes**: You can add a comment to the expense’s chat thread in your Expensify Chat inbox to request changes to the expense details. {% include info.html %} -Admins can modify an expense, if needed. +If the transaction is pending (a common occurrence with recent company card expenses or SmartScan expenses), you’ll need to wait until the transaction posts before approving it. {% include end-info.html %} ![The approve button in an expense]({{site.url}}/assets/images/ExpensifyHelp_ApproveExpense_1.png){:width="100%"} @@ -57,12 +62,28 @@ Once the expense has been approved, you can now pay the expense. Held expenses will not be available for payment until they have been approved. {% include end-info.html %} +# Unapprove an expense + +Some details of approved expenses and reports cannot be edited. If you need to edit an expense that has been approved, admins and the last approver have the option to unapprove reports. + +1. Click the workspace logo in the top left corner. +2. Select the workspace associated with the expense report. +3. Find the approved report by searching for the submitter. +4. Click the dropdown arrow at the top of the report to view the report actions. +5. Click **Unapprove**. + +The unapproved report will return to an editable state, and the submitter will receive an email and chat notification that the expense has been unapproved. + +{% include info.html %} +Reports that have been paid cannot be unapproved. If the approved expense has already been exported to an accounting package, you’ll see a warning that unapproving an expense can cause data discrepancies and Expensify Card reconciliation issues. Ideally, you’ll want to delete the data that has already been exported to the accounting package before approving the expense again. +{% include end-info.html %} + # Pay expenses Once you’ve approved an expense—or if the expense does not require approval—you’ll be able to pay it. {% include info.html %} -To pay expenses within Expensify, you’ll need to set up your Expensify Wallet. +To pay expenses within Expensify, you’ll need to [set up your Expensify Wallet](https://help.expensify.com/articles/new-expensify/expenses-&-payments/Set-up-your-wallet). {% include end-info.html %} To pay an expense, @@ -73,4 +94,14 @@ To pay an expense, - Click **Pay** to pay the full expense within Expensify. If the expenses contain one that has been held, the pay amount will only include the expenses that have not been held. Then you’ll select your payment method. - Click **Pay Elsewhere** to indicate that a payment has been sent using a method outside of Expensify, such as cash or a check. This will label the expense as Paid. +# FAQ + +**Why was an expense automatically approved?** + +We refer to this as **Instant Submit**. If a workspace doesn’t have Delayed Submission enabled, an expense report will automatically be submitted. + +**Why is an employee expense showing as ‘pending?’** + +An Expensify Card expense will show as pending if the merchant hasn’t posted it. This is usually the case with hotel holds, or card rental holds. A hold will normally last no more than 7-10 business days unless it’s a hotel hold, which can last 31 days. +
diff --git a/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md b/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md index 6546f57073ee..1154a6a3163e 100644 --- a/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md +++ b/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md @@ -1,12 +1,38 @@ --- -title: Send an invoice -description: Notify a customer that a payment is due +title: Send an invoice and receive payment +description: steps to send an invoice to someone and receipt payment ---
-You can send invoices directly from Expensify to notify customers that a payment is due. +Workspace admins can enable invoicing on a workspace to send invoices and receive invoice payments through Expensify. -To create and send an invoice, +# Enable invoicing + +{% include selector.html values="desktop, mobile" %} + +{% include option.html value="desktop" %} +1. Click your profile image or icon in the bottom left menu. +2. Scroll down and click **Workspaces** in the left menu. +3. Select the workspace for which you want to enable invoicing. +4. Click **More features** in the left menu. +5. Under the Earn section, enable the Invoice toggle + +{% include end-option.html %} + +{% include option.html value="mobile" %} +1. Tap your profile image or icon in the bottom menu. +2. Tap **Workspaces**. +3. Select the workspace for which you want to enable invoicing. +4. Tap **More features**. +5. Under the Earn section, enable the Invoice toggle. + +{% include end-option.html %} + +# Send an invoice + +{% include info.html %} +Only workspace admins can send invoices. Invoices can be sent directly from Expensify to any customer, even if they do not have an Expensify account. +{% include end-info.html %} {% include selector.html values="desktop, mobile" %} @@ -28,28 +54,38 @@ To create and send an invoice, {% include end-selector.html %} -# How the customer pays an invoice - -Once an invoice is sent, the customer receives an automated email or text message to notify them of the invoice. They can use this notification to pay the invoice whenever they are ready. They will: +# Receive invoice payment -1. Click the link in the email or text notification they receive from Expensify. -2. Click **Pay**. -3. Choose **Paying as an individual** or **Paying as a business**. -4. Click **Pay Elsewhere**, which will mark the invoice as Paid. - -Currently, invoices must be paid outside of Expensify. However, the ability to make payments through Expensify is coming soon. - -![A photo of the pay button]({{site.url}}/assets/images/ExpensifyHelp-Invoice-1.png){:width="100%"} +If you have not [connected a business bank account](https://help.expensify.com/articles/new-expensify/expenses-&-payments/Connect-a-Business-Bank-Account) to receive invoice payments, you will see an **Invoice balance** in your [Wallet](https://help.expensify.com/articles/new-expensify/expenses-&-payments/Set-up-your-wallet). Expensify will automatically transfer these invoice payments once a business bank account is connected. # FAQs +**Why do I need to create a workspace to send an invoice?** + +A workspace is a configuration of settings related to your business. Since invoicing is considered a business feature, you must have a workspace to configure and use invoicing. + **How do I communicate with the sender/recipient about the invoice?** -You can communicate with the recipient in New Expensify. After sending an invoice, Expensify automatically creates an invoice room between the invoice sender and the payer to discuss anything related to the invoice. You can invite users to join the conversation, remove them from the room, and leave the room at any time. +Expensify will automatically notify the invoice recipient about the new invoice via email, SMS, and a mobile app notification, along with instructions on how to pay it. Daily reminders will be sent until the invoice is paid. + +Additionally, an invoice chat room will be automatically created in Expensify between the invoice sender, their workspace admins, and the payer. You can use this chat to discuss anything related to the invoice. + +**Can you export invoices between an accounting integration?** + +Yes, you can export invoices between Expensify and your connected [accounting integration](https://help.expensify.com/new-expensify/hubs/connections/). + +**Who can send and pay an invoice?** + +All workspace admins will be able to send and pay invoices. Invoices can also be paid by anyone, including recipients without an Expensify account. + +**What happens if I disable invoicing in the future?** + +When invoicing is disabled, all previously created invoice rooms and historical invoices will remain unaffected and continue to exist. However, all workspace admins will no longer have the option to send an invoice. + +**Why am I getting an error after I enter my website when connecting a business bank account?** -**Can you import and export invoices between an accounting integration?** +We can only accept a private domain website to ensure the security of your business. If you receive an error when entering your website, it is likely because the domain is not recognized as private. Make sure you are using a business email with a private domain. If you continue to experience issues, contact our support team at concierge@expensify.com for further assistance. -Yes, you can export and import invoices between Expensify and your QuickBooks Online or Xero integration.
diff --git a/docs/articles/new-expensify/expenses-&-payments/pay-an-invoice.md b/docs/articles/new-expensify/expenses-&-payments/pay-an-invoice.md new file mode 100644 index 000000000000..6221117ed962 --- /dev/null +++ b/docs/articles/new-expensify/expenses-&-payments/pay-an-invoice.md @@ -0,0 +1,56 @@ +--- +title: Pay an Invoice +description: process to pay an invoice +--- +
+ +{% include info.html %} +Anyone who receives an Expensify invoice can pay it using Expensify—even if they don’t have an Expensify account. +{% include end-info.html %} + +You'll receive an automated email or text notification when an invoice is sent to you for payment. + +To pay an invoice, + +{% include selector.html values="desktop, mobile" %} + +{% include option.html value="desktop" %} +1. Click the link in the email or text notification you receive from Expensify. +2. Click **Pay**. +3. Choose **Pay as an individual** or **Pay as a business**. +4. Click **Add Bank Account** or **Add debit or credit card** to issue payment. +{% include end-option.html %} + +You can also view all unpaid invoices by searching for the sender’s email or phone number on the left-hand side of the app. The invoices waiting for your payment will have a green dot. + +{% include option.html value="mobile" %} +1. Tap the link in the email or text notification they receive from Expensify. +2. Tap **Pay**. +3. Choose **Pay as an individual** or **Pay as a business**. +4. Tap **Add Bank Account** or **Add debit or credit card** to issue payment. +{% include end-option.html %} + +# FAQ + +**Can someone else pay an invoice besides the person who received it?** + +No, only the person who received the invoice will see the option to pay it. + +**Who can send an invoice?** + +Anyone can pay an invoice they’ve received, but only Expensify customers can send an invoice. This feature ensures that businesses using Expensify can seamlessly manage their invoice billing processes while providing flexibility for their customers to make payments. + +Expensify invoicing is designed to cater to both business-to-customer (B2C) and business-to-business (B2B) needs, making it a versatile tool for businesses of all sizes. + +**Can I pay an invoice outside of Expensify** + +You will need to work with the vendor to discuss alternative payment options. You can chat with your vendor directly at expensify.com in the designated invoice room. + +**Can I add additional payment methods?** + +You can add additional payment methods to your [Wallet](https://help.expensify.com/articles/new-expensify/expenses-&-payments/Set-up-your-wallet). Click **Account Settings** > **Wallet** > click **Add Bank Account**. + +You will be prompted to choose a payment method when paying future invoices. + + +
diff --git a/docs/articles/new-expensify/getting-started/Create-a-company-workspace.md b/docs/articles/new-expensify/getting-started/Create-a-company-workspace.md index f761e8dacd5e..f514360e9519 100644 --- a/docs/articles/new-expensify/getting-started/Create-a-company-workspace.md +++ b/docs/articles/new-expensify/getting-started/Create-a-company-workspace.md @@ -30,11 +30,11 @@ You can get support any time by locating your chat with Concierge in your chat i
  • Click Default Currency to set the currency for all expenses submitted under the workspace. Expensify automatically converts all other currencies to your default currency.
  • -![Click your profile photo or icon]({{site.url}}/assets/images/ExpensifyHelp_R1_CreateWorkspace_1.png){:width="100%"} +![Click your profile photo or icon]({{site.url}}/assets/images/ExpensifyHelp_CreateWorkspace_1.png){:width="100%"} -![Click Workspaces in the left menu and New Worksapce]({{site.url}}/assets/images/ExpensifyHelp_R1_CreateWorkspace_2.png){:width="100%"} +![Click Workspaces in the left menu and New Worksapce]({{site.url}}/assets/images/ExpensifyHelp_CreateWorkspace_2.png){:width="100%"} -![Options to make changes like a custom workspace name]({{site.url}}/assets/images/ExpensifyHelp_R1_CreateWorkspace_3.png){:width="100%"} +![Options to make changes like a custom workspace name]({{site.url}}/assets/images/ExpensifyHelp_CreateWorkspace_3.png){:width="100%"} # 3. Invite members @@ -52,11 +52,11 @@ Once the invite is accepted, the new members will appear in your members list. You can also invite members on the workspace’s Profile page by clicking **Share** to share the workspace’s URL or QR code. {% include end-info.html %} -![Click Members on the left and click Invite member]({{site.url}}/assets/images/ExpensifyHelp_R1_InviteMembers_1.png){:width="100%"} +![Click Members on the left and click Invite member]({{site.url}}/assets/images/ExpensifyHelp_InviteMembers_1.png){:width="100%"} -![Use the search field to find the individual by name, email, or phone number]({{site.url}}/assets/images/ExpensifyHelp_R1_InviteMembers_2.png){:width="100%"} +![Use the search field to find the individual by name, email, or phone number]({{site.url}}/assets/images/ExpensifyHelp_InviteMembers_2.png){:width="100%"} -![Enter a custom message into the Message field]({{site.url}}/assets/images/ExpensifyHelp_R1_InviteMembers_3.png){:width="100%"} +![Enter a custom message into the Message field]({{site.url}}/assets/images/ExpensifyHelp_InviteMembers_3.png){:width="100%"} # 4. Set admins @@ -114,5 +114,7 @@ To add more features, Easily monitor when your Free Trial starts and how many days are left on your Subscription page. We’ll also notify you when your trial starts and ends, at which point you’ll add a billing card to continue using all your favorite features! + +![Hightlight the free trial start and end date]({{site.url}}/assets/images/ExpensifyHelp-FreeTrial-1.png){:width="100%"} diff --git a/docs/assets/Files/Dependent+with+GL+codes+format.csv b/docs/assets/Files/Dependent+with+GL+codes+format.csv new file mode 100644 index 000000000000..830cc1a77f83 --- /dev/null +++ b/docs/assets/Files/Dependent+with+GL+codes+format.csv @@ -0,0 +1 @@ +State,State GL,Region,Region GL,City,City GL California,100,North,20,San Francisco,1 California,100,North,20,Oakland,2 California,100,South,30,Los Angeles,3 California,100,South,30,San Diego,4 \ No newline at end of file diff --git a/docs/assets/Files/Dependent+without+GL+codes+format.csv b/docs/assets/Files/Dependent+without+GL+codes+format.csv new file mode 100644 index 000000000000..394dbfd82dce --- /dev/null +++ b/docs/assets/Files/Dependent+without+GL+codes+format.csv @@ -0,0 +1 @@ +State,Region,City California,North,San Francisco California,North,Oakland California,South,Los Angeles California,South,San Diego \ No newline at end of file diff --git a/docs/assets/Files/Germany-per-diem.csv b/docs/assets/Files/Germany-per-diem.csv new file mode 100644 index 000000000000..217cc0a2fed1 --- /dev/null +++ b/docs/assets/Files/Germany-per-diem.csv @@ -0,0 +1,1417 @@ +Destination,Currency,Subrate,Amount +Afghanistan,EUR,Full Day,30 +Afghanistan,EUR,Part Day,20 +Afghanistan,EUR,Overnight,95 +Afghanistan,EUR,Breakfast,-6 +Afghanistan,EUR,Lunch,-12 +Afghanistan,EUR,Dinner,-12 +Albania,EUR,Full Day,29 +Albania,EUR,Part Day,20 +Albania,EUR,Overnight,113 +Albania,EUR,Breakfast,-5.8 +Albania,EUR,Lunch,-11.6 +Albania,EUR,Dinner,-11.6 +Algeria,EUR,Full Day,51 +Algeria,EUR,Part Day,34 +Algeria,EUR,Overnight,173 +Algeria,EUR,Breakfast,-10.2 +Algeria,EUR,Lunch,-20.4 +Algeria,EUR,Dinner,-20.4 +Andorra,EUR,Full Day,34 +Andorra,EUR,Part Day,23 +Andorra,EUR,Overnight,45 +Andorra,EUR,Breakfast,-6.8 +Andorra,EUR,Lunch,-13.6 +Andorra,EUR,Dinner,-13.6 +Angola,EUR,Full Day,77 +Angola,EUR,Part Day,52 +Angola,EUR,Overnight,265 +Angola,EUR,Breakfast,-15.4 +Angola,EUR,Lunch,-30.8 +Angola,EUR,Dinner,-30.8 +Antigua and Barbuda,EUR,Full Day,45 +Antigua and Barbuda,EUR,Part Day,30 +Antigua and Barbuda,EUR,Overnight,177 +Antigua and Barbuda,EUR,Breakfast,-9 +Antigua and Barbuda,EUR,Lunch,-18 +Antigua and Barbuda,EUR,Dinner,-18 +Argentina,EUR,Full Day,34 +Argentina,EUR,Part Day,23 +Argentina,EUR,Overnight,144 +Argentina,EUR,Breakfast,-6.8 +Argentina,EUR,Lunch,-13.6 +Argentina,EUR,Dinner,-13.6 +Armenia,EUR,Full Day,23 +Armenia,EUR,Part Day,16 +Armenia,EUR,Overnight,63 +Armenia,EUR,Breakfast,-4.6 +Armenia,EUR,Lunch,-9.2 +Armenia,EUR,Dinner,-9.2 +Australia - Canberra,EUR,Full Day,51 +Australia - Canberra,EUR,Part Day,34 +Australia - Canberra,EUR,Overnight,158 +Australia - Canberra,EUR,Breakfast,-10.2 +Australia - Canberra,EUR,Lunch,-20.4 +Australia - Canberra,EUR,Dinner,-20.4 +Australia - Sydney,EUR,Full Day,68 +Australia - Sydney,EUR,Part Day,45 +Australia - Sydney,EUR,Overnight,184 +Australia - Sydney,EUR,Breakfast,-13.6 +Australia - Sydney,EUR,Lunch,-27.2 +Australia - Sydney,EUR,Dinner,-27.2 +Australia - for the rest,EUR,Full Day,51 +Australia - for the rest,EUR,Part Day,34 +Australia - for the rest,EUR,Overnight,158 +Australia - for the rest,EUR,Breakfast,-10.2 +Australia - for the rest,EUR,Lunch,-20.4 +Australia - for the rest,EUR,Dinner,-20.4 +Austria,EUR,Full Day,40 +Austria,EUR,Part Day,27 +Austria,EUR,Overnight,108 +Austria,EUR,Breakfast,-8 +Austria,EUR,Lunch,-16 +Austria,EUR,Dinner,-16 +Azerbaijan,EUR,Full Day,30 +Azerbaijan,EUR,Part Day,20 +Azerbaijan,EUR,Overnight,72 +Azerbaijan,EUR,Breakfast,-6 +Azerbaijan,EUR,Lunch,-12 +Azerbaijan,EUR,Dinner,-12 +Bahrain,EUR,Full Day,45 +Bahrain,EUR,Part Day,30 +Bahrain,EUR,Overnight,180 +Bahrain,EUR,Breakfast,-9 +Bahrain,EUR,Lunch,-18 +Bahrain,EUR,Dinner,-18 +Bangladesh,EUR,Full Day,30 +Bangladesh,EUR,Part Day,20 +Bangladesh,EUR,Overnight,111 +Bangladesh,EUR,Breakfast,-6 +Bangladesh,EUR,Lunch,-12 +Bangladesh,EUR,Dinner,-12 +Barbados,EUR,Full Day,52 +Barbados,EUR,Part Day,35 +Barbados,EUR,Overnight,165 +Barbados,EUR,Breakfast,-10.4 +Barbados,EUR,Lunch,-20.8 +Barbados,EUR,Dinner,-20.8 +Belarus,EUR,Full Day,20 +Belarus,EUR,Part Day,13 +Belarus,EUR,Overnight,98 +Belarus,EUR,Breakfast,-4 +Belarus,EUR,Lunch,-8 +Belarus,EUR,Dinner,-8 +Belgium,EUR,Full Day,42 +Belgium,EUR,Part Day,28 +Belgium,EUR,Overnight,135 +Belgium,EUR,Breakfast,-8.4 +Belgium,EUR,Lunch,-16.8 +Belgium,EUR,Dinner,-16.8 +Benin,EUR,Full Day,40 +Benin,EUR,Part Day,27 +Benin,EUR,Overnight,101 +Benin,EUR,Breakfast,-8 +Benin,EUR,Lunch,-16 +Benin,EUR,Dinner,-16 +Bolivia,EUR,Full Day,30 +Bolivia,EUR,Part Day,20 +Bolivia,EUR,Overnight,93 +Bolivia,EUR,Breakfast,-6 +Bolivia,EUR,Lunch,-12 +Bolivia,EUR,Dinner,-12 +Bosnia and Herzegovina,EUR,Full Day,18 +Bosnia and Herzegovina,EUR,Part Day,12 +Bosnia and Herzegovina,EUR,Overnight,73 +Bosnia and Herzegovina,EUR,Breakfast,-3.6 +Bosnia and Herzegovina,EUR,Lunch,-7.2 +Bosnia and Herzegovina,EUR,Dinner,-7.2 +Botswana,EUR,Full Day,40 +Botswana,EUR,Part Day,27 +Botswana,EUR,Overnight,102 +Botswana,EUR,Breakfast,-8 +Botswana,EUR,Lunch,-16 +Botswana,EUR,Dinner,-16 +Brazil - Brasilia,EUR,Full Day,57 +Brazil - Brasilia,EUR,Part Day,38 +Brazil - Brasilia,EUR,Overnight,127 +Brazil - Brasilia,EUR,Breakfast,-11.4 +Brazil - Brasilia,EUR,Lunch,-22.8 +Brazil - Brasilia,EUR,Dinner,-22.8 +Brazil - Rio de Janeiro,EUR,Full Day,57 +Brazil - Rio de Janeiro,EUR,Part Day,38 +Brazil - Rio de Janeiro,EUR,Overnight,145 +Brazil - Rio de Janeiro,EUR,Breakfast,-11.4 +Brazil - Rio de Janeiro,EUR,Lunch,-22.8 +Brazil - Rio de Janeiro,EUR,Dinner,-22.8 +Brazil - São Paulo,EUR,Full Day,53 +Brazil - São Paulo,EUR,Part Day,36 +Brazil - São Paulo,EUR,Overnight,132 +Brazil - São Paulo,EUR,Breakfast,-10.6 +Brazil - São Paulo,EUR,Lunch,-21.2 +Brazil - São Paulo,EUR,Dinner,-21.2 +Brazil - for the rest,EUR,Full Day,51 +Brazil - for the rest,EUR,Part Day,34 +Brazil - for the rest,EUR,Overnight,84 +Brazil - for the rest,EUR,Breakfast,-10.2 +Brazil - for the rest,EUR,Lunch,-20.4 +Brazil - for the rest,EUR,Dinner,-20.4 +Brunei,EUR,Full Day,48 +Brunei,EUR,Part Day,32 +Brunei,EUR,Overnight,106 +Brunei,EUR,Breakfast,-9.6 +Brunei,EUR,Lunch,-19.2 +Brunei,EUR,Dinner,-19.2 +Bulgaria,EUR,Full Day,22 +Bulgaria,EUR,Part Day,15 +Bulgaria,EUR,Overnight,90 +Bulgaria,EUR,Breakfast,-4.4 +Bulgaria,EUR,Lunch,-8.8 +Bulgaria,EUR,Dinner,-8.8 +Burkina Faso,EUR,Full Day,44 +Burkina Faso,EUR,Part Day,29 +Burkina Faso,EUR,Overnight,84 +Burkina Faso,EUR,Breakfast,-8.8 +Burkina Faso,EUR,Lunch,-17.6 +Burkina Faso,EUR,Dinner,-17.6 +Burundi,EUR,Full Day,47 +Burundi,EUR,Part Day,32 +Burundi,EUR,Overnight,98 +Burundi,EUR,Breakfast,-9.4 +Burundi,EUR,Lunch,-18.8 +Burundi,EUR,Dinner,-18.8 +Cambodia,EUR,Full Day,38 +Cambodia,EUR,Part Day,25 +Cambodia,EUR,Overnight,94 +Cambodia,EUR,Breakfast,-7.6 +Cambodia,EUR,Lunch,-15.2 +Cambodia,EUR,Dinner,-15.2 +Cameroon,EUR,Full Day,50 +Cameroon,EUR,Part Day,33 +Cameroon,EUR,Overnight,180 +Cameroon,EUR,Breakfast,-10 +Cameroon,EUR,Lunch,-20 +Cameroon,EUR,Dinner,-20 +Canada - Ottawa,EUR,Full Day,47 +Canada - Ottawa,EUR,Part Day,32 +Canada - Ottawa,EUR,Overnight,142 +Canada - Ottawa,EUR,Breakfast,-9.4 +Canada - Ottawa,EUR,Lunch,-18.8 +Canada - Ottawa,EUR,Dinner,-18.8 +Canada - Toronto,EUR,Full Day,51 +Canada - Toronto,EUR,Part Day,34 +Canada - Toronto,EUR,Overnight,161 +Canada - Toronto,EUR,Breakfast,-10.2 +Canada - Toronto,EUR,Lunch,-20.4 +Canada - Toronto,EUR,Dinner,-20.4 +Canada - Vancouver,EUR,Full Day,50 +Canada - Vancouver,EUR,Part Day,33 +Canada - Vancouver,EUR,Overnight,140 +Canada - Vancouver,EUR,Breakfast,-10 +Canada - Vancouver,EUR,Lunch,-20 +Canada - Vancouver,EUR,Dinner,-20 +Canada - for the rest,EUR,Full Day,47 +Canada - for the rest,EUR,Part Day,32 +Canada - for the rest,EUR,Overnight,134 +Canada - for the rest,EUR,Breakfast,-9.4 +Canada - for the rest,EUR,Lunch,-18.8 +Canada - for the rest,EUR,Dinner,-18.8 +Cape Verde,EUR,Full Day,30 +Cape Verde,EUR,Part Day,20 +Cape Verde,EUR,Overnight,105 +Cape Verde,EUR,Breakfast,-6 +Cape Verde,EUR,Lunch,-12 +Cape Verde,EUR,Dinner,-12 +Central African Republic,EUR,Full Day,46 +Central African Republic,EUR,Part Day,31 +Central African Republic,EUR,Overnight,74 +Central African Republic,EUR,Breakfast,-9.2 +Central African Republic,EUR,Lunch,-18.4 +Central African Republic,EUR,Dinner,-18.4 +Chad,EUR,Full Day,64 +Chad,EUR,Part Day,43 +Chad,EUR,Overnight,163 +Chad,EUR,Breakfast,-12.8 +Chad,EUR,Lunch,-25.6 +Chad,EUR,Dinner,-25.6 +Chile,EUR,Full Day,44 +Chile,EUR,Part Day,29 +Chile,EUR,Overnight,187 +Chile,EUR,Breakfast,-8.8 +Chile,EUR,Lunch,-17.6 +Chile,EUR,Dinner,-17.6 +China - Beijing,EUR,Full Day,46 +China - Beijing,EUR,Part Day,31 +China - Beijing,EUR,Overnight,142 +China - Beijing,EUR,Breakfast,-9.2 +China - Beijing,EUR,Lunch,-18.4 +China - Beijing,EUR,Dinner,-18.4 +China - Canton,EUR,Full Day,40 +China - Canton,EUR,Part Day,27 +China - Canton,EUR,Overnight,113 +China - Canton,EUR,Breakfast,-8 +China - Canton,EUR,Lunch,-16 +China - Canton,EUR,Dinner,-16 +China - Chengdu,EUR,Full Day,35 +China - Chengdu,EUR,Part Day,24 +China - Chengdu,EUR,Overnight,105 +China - Chengdu,EUR,Breakfast,-7 +China - Chengdu,EUR,Lunch,-14 +China - Chengdu,EUR,Dinner,-14 +China - Hong Kong,EUR,Full Day,74 +China - Hong Kong,EUR,Part Day,49 +China - Hong Kong,EUR,Overnight,145 +China - Hong Kong,EUR,Breakfast,-14.8 +China - Hong Kong,EUR,Lunch,-29.6 +China - Hong Kong,EUR,Dinner,-29.6 +China - Shanghai,EUR,Full Day,50 +China - Shanghai,EUR,Part Day,33 +China - Shanghai,EUR,Overnight,128 +China - Shanghai,EUR,Breakfast,-10 +China - Shanghai,EUR,Lunch,-20 +China - Shanghai,EUR,Dinner,-20 +China - for the rest,EUR,Full Day,50 +China - for the rest,EUR,Part Day,33 +China - for the rest,EUR,Overnight,78 +China - for the rest,EUR,Breakfast,-10 +China - for the rest,EUR,Lunch,-20 +China - for the rest,EUR,Dinner,-20 +Colombia,EUR,Full Day,41 +Colombia,EUR,Part Day,28 +Colombia,EUR,Overnight,126 +Colombia,EUR,Breakfast,-8.2 +Colombia,EUR,Lunch,-16.4 +Colombia,EUR,Dinner,-16.4 +"Congo, Democratic Republic",EUR,Full Day,68 +"Congo, Democratic Republic",EUR,Part Day,45 +"Congo, Democratic Republic",EUR,Overnight,171 +"Congo, Democratic Republic",EUR,Breakfast,-13.6 +"Congo, Democratic Republic",EUR,Lunch,-27.2 +"Congo, Democratic Republic",EUR,Dinner,-27.2 +"Congo, Republic",EUR,Full Day,50 +"Congo, Republic",EUR,Part Day,33 +"Congo, Republic",EUR,Overnight,200 +"Congo, Republic",EUR,Breakfast,-10 +"Congo, Republic",EUR,Lunch,-20 +"Congo, Republic",EUR,Dinner,-20 +Costa Rica,EUR,Full Day,47 +Costa Rica,EUR,Part Day,32 +Costa Rica,EUR,Overnight,93 +Costa Rica,EUR,Breakfast,-9.4 +Costa Rica,EUR,Lunch,-18.8 +Costa Rica,EUR,Dinner,-18.8 +Côte d’Ivoire,EUR,Full Day,51 +Côte d’Ivoire,EUR,Part Day,34 +Côte d’Ivoire,EUR,Overnight,146 +Côte d’Ivoire,EUR,Breakfast,-10.2 +Côte d’Ivoire,EUR,Lunch,-20.4 +Côte d’Ivoire,EUR,Dinner,-20.4 +Croatia,EUR,Full Day,28 +Croatia,EUR,Part Day,19 +Croatia,EUR,Overnight,75 +Croatia,EUR,Breakfast,-5.6 +Croatia,EUR,Lunch,-11.2 +Croatia,EUR,Dinner,-11.2 +Cuba,EUR,Full Day,46 +Cuba,EUR,Part Day,31 +Cuba,EUR,Overnight,228 +Cuba,EUR,Breakfast,-9.2 +Cuba,EUR,Lunch,-18.4 +Cuba,EUR,Dinner,-18.4 +Cyprus,EUR,Full Day,45 +Cyprus,EUR,Part Day,30 +Cyprus,EUR,Overnight,116 +Cyprus,EUR,Breakfast,-9 +Cyprus,EUR,Lunch,-18 +Cyprus,EUR,Dinner,-18 +Czech Republic,EUR,Full Day,35 +Czech Republic,EUR,Part Day,24 +Czech Republic,EUR,Overnight,94 +Czech Republic,EUR,Breakfast,-7 +Czech Republic,EUR,Lunch,-14 +Czech Republic,EUR,Dinner,-14 +Denmark,EUR,Full Day,58 +Denmark,EUR,Part Day,39 +Denmark,EUR,Overnight,143 +Denmark,EUR,Breakfast,-11.6 +Denmark,EUR,Lunch,-23.2 +Denmark,EUR,Dinner,-23.2 +Djibouti,EUR,Full Day,65 +Djibouti,EUR,Part Day,44 +Djibouti,EUR,Overnight,305 +Djibouti,EUR,Breakfast,-13 +Djibouti,EUR,Lunch,-26 +Djibouti,EUR,Dinner,-26 +Dominica,EUR,Full Day,45 +Dominica,EUR,Part Day,30 +Dominica,EUR,Overnight,177 +Dominica,EUR,Breakfast,-9 +Dominica,EUR,Lunch,-18 +Dominica,EUR,Dinner,-18 +Dominican Republic,EUR,Full Day,45 +Dominican Republic,EUR,Part Day,30 +Dominican Republic,EUR,Overnight,147 +Dominican Republic,EUR,Breakfast,-9 +Dominican Republic,EUR,Lunch,-18 +Dominican Republic,EUR,Dinner,-18 +Ecuador,EUR,Full Day,44 +Ecuador,EUR,Part Day,29 +Ecuador,EUR,Overnight,97 +Ecuador,EUR,Breakfast,-8.8 +Ecuador,EUR,Lunch,-17.6 +Ecuador,EUR,Dinner,-17.6 +Egypt,EUR,Full Day,41 +Egypt,EUR,Part Day,28 +Egypt,EUR,Overnight,125 +Egypt,EUR,Breakfast,-8.2 +Egypt,EUR,Lunch,-16.4 +Egypt,EUR,Dinner,-16.4 +El Salvador,EUR,Full Day,44 +El Salvador,EUR,Part Day,29 +El Salvador,EUR,Overnight,119 +El Salvador,EUR,Breakfast,-8.8 +El Salvador,EUR,Lunch,-17.6 +El Salvador,EUR,Dinner,-17.6 +Equatorial Guinea,EUR,Full Day,36 +Equatorial Guinea,EUR,Part Day,24 +Equatorial Guinea,EUR,Overnight,166 +Equatorial Guinea,EUR,Breakfast,-7.2 +Equatorial Guinea,EUR,Lunch,-14.4 +Equatorial Guinea,EUR,Dinner,-14.4 +Eritrea,EUR,Full Day,50 +Eritrea,EUR,Part Day,33 +Eritrea,EUR,Overnight,91 +Eritrea,EUR,Breakfast,-10 +Eritrea,EUR,Lunch,-20 +Eritrea,EUR,Dinner,-20 +Estonia,EUR,Full Day,27 +Estonia,EUR,Part Day,18 +Estonia,EUR,Overnight,71 +Estonia,EUR,Breakfast,-5.4 +Estonia,EUR,Lunch,-10.8 +Estonia,EUR,Dinner,-10.8 +Ethiopia,EUR,Full Day,27 +Ethiopia,EUR,Part Day,18 +Ethiopia,EUR,Overnight,86 +Ethiopia,EUR,Breakfast,-5.4 +Ethiopia,EUR,Lunch,-10.8 +Ethiopia,EUR,Dinner,-10.8 +Fiji,EUR,Full Day,34 +Fiji,EUR,Part Day,23 +Fiji,EUR,Overnight,69 +Fiji,EUR,Breakfast,-6.8 +Fiji,EUR,Lunch,-13.6 +Fiji,EUR,Dinner,-13.6 +Finland,EUR,Full Day,50 +Finland,EUR,Part Day,33 +Finland,EUR,Overnight,136 +Finland,EUR,Breakfast,-10 +Finland,EUR,Lunch,-20 +Finland,EUR,Dinner,-20 +France - Lyon,EUR,Full Day,53 +France - Lyon,EUR,Part Day,36 +France - Lyon,EUR,Overnight,115 +France - Lyon,EUR,Breakfast,-10.6 +France - Lyon,EUR,Lunch,-21.2 +France - Lyon,EUR,Dinner,-21.2 +France - Marseille,EUR,Full Day,46 +France - Marseille,EUR,Part Day,31 +France - Marseille,EUR,Overnight,101 +France - Marseille,EUR,Breakfast,-9.2 +France - Marseille,EUR,Lunch,-18.4 +France - Marseille,EUR,Dinner,-18.4 +"France - Paris and Departments 92, 93 and 94",EUR,Full Day,58 +"France - Paris and Departments 92, 93 and 94",EUR,Part Day,39 +"France - Paris and Departments 92, 93 and 94",EUR,Overnight,152 +"France - Paris and Departments 92, 93 and 94",EUR,Breakfast,-11.6 +"France - Paris and Departments 92, 93 and 94",EUR,Lunch,-23.2 +"France - Paris and Departments 92, 93 and 94",EUR,Dinner,-23.2 +France - Strasbourg,EUR,Full Day,51 +France - Strasbourg,EUR,Part Day,34 +France - Strasbourg,EUR,Overnight,96 +France - Strasbourg,EUR,Breakfast,-10.2 +France - Strasbourg,EUR,Lunch,-20.4 +France - Strasbourg,EUR,Dinner,-20.4 +France - for the rest,EUR,Full Day,44 +France - for the rest,EUR,Part Day,29 +France - for the rest,EUR,Overnight,115 +France - for the rest,EUR,Breakfast,-8.8 +France - for the rest,EUR,Lunch,-17.6 +France - for the rest,EUR,Dinner,-17.6 +Gabon,EUR,Full Day,62 +Gabon,EUR,Part Day,41 +Gabon,EUR,Overnight,278 +Gabon,EUR,Breakfast,-12.4 +Gabon,EUR,Lunch,-24.8 +Gabon,EUR,Dinner,-24.8 +Gambia,EUR,Full Day,30 +Gambia,EUR,Part Day,20 +Gambia,EUR,Overnight,125 +Gambia,EUR,Breakfast,-6 +Gambia,EUR,Lunch,-12 +Gambia,EUR,Dinner,-12 +Georgia,EUR,Full Day,35 +Georgia,EUR,Part Day,24 +Georgia,EUR,Overnight,88 +Georgia,EUR,Breakfast,-7 +Georgia,EUR,Lunch,-14 +Georgia,EUR,Dinner,-14 +Ghana,EUR,Full Day,46 +Ghana,EUR,Part Day,31 +Ghana,EUR,Overnight,148 +Ghana,EUR,Breakfast,-9.2 +Ghana,EUR,Lunch,-18.4 +Ghana,EUR,Dinner,-18.4 +Greece - Athens,EUR,Full Day,46 +Greece - Athens,EUR,Part Day,31 +Greece - Athens,EUR,Overnight,132 +Greece - Athens,EUR,Breakfast,-9.2 +Greece - Athens,EUR,Lunch,-18.4 +Greece - Athens,EUR,Dinner,-18.4 +Greece - for the rest,EUR,Full Day,36 +Greece - for the rest,EUR,Part Day,24 +Greece - for the rest,EUR,Overnight,135 +Greece - for the rest,EUR,Breakfast,-7.2 +Greece - for the rest,EUR,Lunch,-14.4 +Greece - for the rest,EUR,Dinner,-14.4 +Grenada,EUR,Full Day,45 +Grenada,EUR,Part Day,30 +Grenada,EUR,Overnight,177 +Grenada,EUR,Breakfast,-9 +Grenada,EUR,Lunch,-18 +Grenada,EUR,Dinner,-18 +Guatemala,EUR,Full Day,34 +Guatemala,EUR,Part Day,23 +Guatemala,EUR,Overnight,90 +Guatemala,EUR,Breakfast,-6.8 +Guatemala,EUR,Lunch,-13.6 +Guatemala,EUR,Dinner,-13.6 +Guinea,EUR,Full Day,46 +Guinea,EUR,Part Day,31 +Guinea,EUR,Overnight,118 +Guinea,EUR,Breakfast,-9.2 +Guinea,EUR,Lunch,-18.4 +Guinea,EUR,Dinner,-18.4 +Guinea-Bissau,EUR,Full Day,24 +Guinea-Bissau,EUR,Part Day,16 +Guinea-Bissau,EUR,Overnight,86 +Guinea-Bissau,EUR,Breakfast,-4.8 +Guinea-Bissau,EUR,Lunch,-9.6 +Guinea-Bissau,EUR,Dinner,-9.6 +Guyana,EUR,Full Day,45 +Guyana,EUR,Part Day,30 +Guyana,EUR,Overnight,177 +Guyana,EUR,Breakfast,-9 +Guyana,EUR,Lunch,-18 +Guyana,EUR,Dinner,-18 +Haiti,EUR,Full Day,58 +Haiti,EUR,Part Day,39 +Haiti,EUR,Overnight,130 +Haiti,EUR,Breakfast,-11.6 +Haiti,EUR,Lunch,-23.2 +Haiti,EUR,Dinner,-23.2 +Honduras,EUR,Full Day,48 +Honduras,EUR,Part Day,32 +Honduras,EUR,Overnight,101 +Honduras,EUR,Breakfast,-9.6 +Honduras,EUR,Lunch,-19.2 +Honduras,EUR,Dinner,-19.2 +Hungary,EUR,Full Day,22 +Hungary,EUR,Part Day,15 +Hungary,EUR,Overnight,63 +Hungary,EUR,Breakfast,-4.4 +Hungary,EUR,Lunch,-8.8 +Hungary,EUR,Dinner,-8.8 +Iceland,EUR,Full Day,47 +Iceland,EUR,Part Day,32 +Iceland,EUR,Overnight,108 +Iceland,EUR,Breakfast,-9.4 +Iceland,EUR,Lunch,-18.8 +Iceland,EUR,Dinner,-18.8 +India - Chennai,EUR,Full Day,32 +India - Chennai,EUR,Part Day,21 +India - Chennai,EUR,Overnight,85 +India - Chennai,EUR,Breakfast,-6.4 +India - Chennai,EUR,Lunch,-12.8 +India - Chennai,EUR,Dinner,-12.8 +India - Kolkata,EUR,Full Day,35 +India - Kolkata,EUR,Part Day,24 +India - Kolkata,EUR,Overnight,145 +India - Kolkata,EUR,Breakfast,-7 +India - Kolkata,EUR,Lunch,-14 +India - Kolkata,EUR,Dinner,-14 +India - Mumbai,EUR,Full Day,50 +India - Mumbai,EUR,Part Day,33 +India - Mumbai,EUR,Overnight,146 +India - Mumbai,EUR,Breakfast,-10 +India - Mumbai,EUR,Lunch,-20 +India - Mumbai,EUR,Dinner,-20 +India - New Delhi,EUR,Full Day,38 +India - New Delhi,EUR,Part Day,25 +India - New Delhi,EUR,Overnight,185 +India - New Delhi,EUR,Breakfast,-7.6 +India - New Delhi,EUR,Lunch,-15.2 +India - New Delhi,EUR,Dinner,-15.2 +India - for the rest,EUR,Full Day,32 +India - for the rest,EUR,Part Day,21 +India - for the rest,EUR,Overnight,85 +India - for the rest,EUR,Breakfast,-6.4 +India - for the rest,EUR,Lunch,-12.8 +India - for the rest,EUR,Dinner,-12.8 +Indonesia,EUR,Full Day,38 +Indonesia,EUR,Part Day,25 +Indonesia,EUR,Overnight,130 +Indonesia,EUR,Breakfast,-7.6 +Indonesia,EUR,Lunch,-15.2 +Indonesia,EUR,Dinner,-15.2 +Iran,EUR,Full Day,33 +Iran,EUR,Part Day,22 +Iran,EUR,Overnight,196 +Iran,EUR,Breakfast,-6.6 +Iran,EUR,Lunch,-13.2 +Iran,EUR,Dinner,-13.2 +Ireland,EUR,Full Day,44 +Ireland,EUR,Part Day,29 +Ireland,EUR,Overnight,92 +Ireland,EUR,Breakfast,-8.8 +Ireland,EUR,Lunch,-17.6 +Ireland,EUR,Dinner,-17.6 +Israel,EUR,Full Day,56 +Israel,EUR,Part Day,37 +Israel,EUR,Overnight,191 +Israel,EUR,Breakfast,-11.2 +Israel,EUR,Lunch,-22.4 +Israel,EUR,Dinner,-22.4 +Italy - Milan,EUR,Full Day,45 +Italy - Milan,EUR,Part Day,30 +Italy - Milan,EUR,Overnight,158 +Italy - Milan,EUR,Breakfast,-9 +Italy - Milan,EUR,Lunch,-18 +Italy - Milan,EUR,Dinner,-18 +Italy - Rome,EUR,Full Day,40 +Italy - Rome,EUR,Part Day,27 +Italy - Rome,EUR,Overnight,135 +Italy - Rome,EUR,Breakfast,-8 +Italy - Rome,EUR,Lunch,-16 +Italy - Rome,EUR,Dinner,-16 +Italy - for the rest,EUR,Full Day,40 +Italy - for the rest,EUR,Part Day,27 +Italy - for the rest,EUR,Overnight,135 +Italy - for the rest,EUR,Breakfast,-8 +Italy - for the rest,EUR,Lunch,-16 +Italy - for the rest,EUR,Dinner,-16 +Jamaica,EUR,Full Day,57 +Jamaica,EUR,Part Day,38 +Jamaica,EUR,Overnight,138 +Jamaica,EUR,Breakfast,-11.4 +Jamaica,EUR,Lunch,-22.8 +Jamaica,EUR,Dinner,-22.8 +Japan - Tokyo,EUR,Full Day,66 +Japan - Tokyo,EUR,Part Day,44 +Japan - Tokyo,EUR,Overnight,233 +Japan - Tokyo,EUR,Breakfast,-13.2 +Japan - Tokyo,EUR,Lunch,-26.4 +Japan - Tokyo,EUR,Dinner,-26.4 +Japan - for the rest,EUR,Full Day,51 +Japan - for the rest,EUR,Part Day,34 +Japan - for the rest,EUR,Overnight,156 +Japan - for the rest,EUR,Breakfast,-10.2 +Japan - for the rest,EUR,Lunch,-20.4 +Japan - for the rest,EUR,Dinner,-20.4 +Jordan,EUR,Full Day,46 +Jordan,EUR,Part Day,31 +Jordan,EUR,Overnight,126 +Jordan,EUR,Breakfast,-9.2 +Jordan,EUR,Lunch,-18.4 +Jordan,EUR,Dinner,-18.4 +Kazakhstan,EUR,Full Day,45 +Kazakhstan,EUR,Part Day,30 +Kazakhstan,EUR,Overnight,111 +Kazakhstan,EUR,Breakfast,-9 +Kazakhstan,EUR,Lunch,-18 +Kazakhstan,EUR,Dinner,-18 +Kenya,EUR,Full Day,42 +Kenya,EUR,Part Day,28 +Kenya,EUR,Overnight,223 +Kenya,EUR,Breakfast,-8.4 +Kenya,EUR,Lunch,-16.8 +Kenya,EUR,Dinner,-16.8 +"Korea, Democratic People's Republic",EUR,Full Day,39 +"Korea, Democratic People's Republic",EUR,Part Day,26 +"Korea, Democratic People's Republic",EUR,Overnight,132 +"Korea, Democratic People's Republic",EUR,Breakfast,-7.8 +"Korea, Democratic People's Republic",EUR,Lunch,-15.6 +"Korea, Democratic People's Republic",EUR,Dinner,-15.6 +"Korea, People's Republic",EUR,Full Day,58 +"Korea, People's Republic",EUR,Part Day,39 +"Korea, People's Republic",EUR,Overnight,112 +"Korea, People's Republic",EUR,Breakfast,-11.6 +"Korea, People's Republic",EUR,Lunch,-23.2 +"Korea, People's Republic",EUR,Dinner,-23.2 +Kosovo,EUR,Full Day,23 +Kosovo,EUR,Part Day,16 +Kosovo,EUR,Overnight,57 +Kosovo,EUR,Breakfast,-4.6 +Kosovo,EUR,Lunch,-9.2 +Kosovo,EUR,Dinner,-9.2 +Kuwait,EUR,Full Day,42 +Kuwait,EUR,Part Day,28 +Kuwait,EUR,Overnight,185 +Kuwait,EUR,Breakfast,-8.4 +Kuwait,EUR,Lunch,-16.8 +Kuwait,EUR,Dinner,-16.8 +Kyrgyzstan,EUR,Full Day,29 +Kyrgyzstan,EUR,Part Day,20 +Kyrgyzstan,EUR,Overnight,91 +Kyrgyzstan,EUR,Breakfast,-5.8 +Kyrgyzstan,EUR,Lunch,-11.6 +Kyrgyzstan,EUR,Dinner,-11.6 +Laos,EUR,Full Day,33 +Laos,EUR,Part Day,22 +Laos,EUR,Overnight,96 +Laos,EUR,Breakfast,-6.6 +Laos,EUR,Lunch,-13.2 +Laos,EUR,Dinner,-13.2 +Latvia,EUR,Full Day,30 +Latvia,EUR,Part Day,20 +Latvia,EUR,Overnight,80 +Latvia,EUR,Breakfast,-6 +Latvia,EUR,Lunch,-12 +Latvia,EUR,Dinner,-12 +Lebanon,EUR,Full Day,59 +Lebanon,EUR,Part Day,40 +Lebanon,EUR,Overnight,123 +Lebanon,EUR,Breakfast,-11.8 +Lebanon,EUR,Lunch,-23.6 +Lebanon,EUR,Dinner,-23.6 +Lesotho,EUR,Full Day,24 +Lesotho,EUR,Part Day,16 +Lesotho,EUR,Overnight,103 +Lesotho,EUR,Breakfast,-4.8 +Lesotho,EUR,Lunch,-9.6 +Lesotho,EUR,Dinner,-9.6 +Libya,EUR,Full Day,63 +Libya,EUR,Part Day,42 +Libya,EUR,Overnight,135 +Libya,EUR,Breakfast,-12.6 +Libya,EUR,Lunch,-25.2 +Libya,EUR,Dinner,-25.2 +Liechtenstein,EUR,Full Day,53 +Liechtenstein,EUR,Part Day,36 +Liechtenstein,EUR,Overnight,180 +Liechtenstein,EUR,Breakfast,-10.6 +Liechtenstein,EUR,Lunch,-21.2 +Liechtenstein,EUR,Dinner,-21.2 +Lithuania,EUR,Full Day,24 +Lithuania,EUR,Part Day,16 +Lithuania,EUR,Overnight,68 +Lithuania,EUR,Breakfast,-4.8 +Lithuania,EUR,Lunch,-9.6 +Lithuania,EUR,Dinner,-9.6 +Luxembourg,EUR,Full Day,47 +Luxembourg,EUR,Part Day,32 +Luxembourg,EUR,Overnight,130 +Luxembourg,EUR,Breakfast,-9.4 +Luxembourg,EUR,Lunch,-18.8 +Luxembourg,EUR,Dinner,-18.8 +Macedonia,EUR,Full Day,29 +Macedonia,EUR,Part Day,20 +Macedonia,EUR,Overnight,95 +Macedonia,EUR,Breakfast,-5.8 +Macedonia,EUR,Lunch,-11.6 +Macedonia,EUR,Dinner,-11.6 +Madagascar,EUR,Full Day,34 +Madagascar,EUR,Part Day,23 +Madagascar,EUR,Overnight,87 +Madagascar,EUR,Breakfast,-6.8 +Madagascar,EUR,Lunch,-13.6 +Madagascar,EUR,Dinner,-13.6 +Malawi,EUR,Full Day,47 +Malawi,EUR,Part Day,32 +Malawi,EUR,Overnight,123 +Malawi,EUR,Breakfast,-9.4 +Malawi,EUR,Lunch,-18.8 +Malawi,EUR,Dinner,-18.8 +Malaysia,EUR,Full Day,34 +Malaysia,EUR,Part Day,23 +Malaysia,EUR,Overnight,88 +Malaysia,EUR,Breakfast,-6.8 +Malaysia,EUR,Lunch,-13.6 +Malaysia,EUR,Dinner,-13.6 +Maldives,EUR,Full Day,52 +Maldives,EUR,Part Day,35 +Maldives,EUR,Overnight,170 +Maldives,EUR,Breakfast,-10.4 +Maldives,EUR,Lunch,-20.8 +Maldives,EUR,Dinner,-20.8 +Mali,EUR,Full Day,41 +Mali,EUR,Part Day,28 +Mali,EUR,Overnight,122 +Mali,EUR,Breakfast,-8.2 +Mali,EUR,Lunch,-16.4 +Mali,EUR,Dinner,-16.4 +Malta,EUR,Full Day,45 +Malta,EUR,Part Day,30 +Malta,EUR,Overnight,112 +Malta,EUR,Breakfast,-9 +Malta,EUR,Lunch,-18 +Malta,EUR,Dinner,-18 +Marshall Islands,EUR,Full Day,63 +Marshall Islands,EUR,Part Day,42 +Marshall Islands,EUR,Overnight,102 +Marshall Islands,EUR,Breakfast,-12.6 +Marshall Islands,EUR,Lunch,-25.2 +Marshall Islands,EUR,Dinner,-25.2 +Mauritania,EUR,Full Day,39 +Mauritania,EUR,Part Day,26 +Mauritania,EUR,Overnight,105 +Mauritania,EUR,Breakfast,-7.8 +Mauritania,EUR,Lunch,-15.6 +Mauritania,EUR,Dinner,-15.6 +Mauritius,EUR,Full Day,54 +Mauritius,EUR,Part Day,36 +Mauritius,EUR,Overnight,220 +Mauritius,EUR,Breakfast,-10.8 +Mauritius,EUR,Lunch,-21.6 +Mauritius,EUR,Dinner,-21.6 +Mexico,EUR,Full Day,41 +Mexico,EUR,Part Day,28 +Mexico,EUR,Overnight,141 +Mexico,EUR,Breakfast,-8.2 +Mexico,EUR,Lunch,-16.4 +Mexico,EUR,Dinner,-16.4 +Micronesia,EUR,Full Day,33 +Micronesia,EUR,Part Day,22 +Micronesia,EUR,Overnight,116 +Micronesia,EUR,Breakfast,-6.6 +Micronesia,EUR,Lunch,-13.2 +Micronesia,EUR,Dinner,-13.2 +"Moldova, Republic",EUR,Full Day,24 +"Moldova, Republic",EUR,Part Day,16 +"Moldova, Republic",EUR,Overnight,88 +"Moldova, Republic",EUR,Breakfast,-4.8 +"Moldova, Republic",EUR,Lunch,-9.6 +"Moldova, Republic",EUR,Dinner,-9.6 +Monaco,EUR,Full Day,42 +Monaco,EUR,Part Day,28 +Monaco,EUR,Overnight,180 +Monaco,EUR,Breakfast,-8.4 +Monaco,EUR,Lunch,-16.8 +Monaco,EUR,Dinner,-16.8 +Mongolia,EUR,Full Day,27 +Mongolia,EUR,Part Day,18 +Mongolia,EUR,Overnight,92 +Mongolia,EUR,Breakfast,-5.4 +Mongolia,EUR,Lunch,-10.8 +Mongolia,EUR,Dinner,-10.8 +Montenegro,EUR,Full Day,29 +Montenegro,EUR,Part Day,20 +Montenegro,EUR,Overnight,94 +Montenegro,EUR,Breakfast,-5.8 +Montenegro,EUR,Lunch,-11.6 +Montenegro,EUR,Dinner,-11.6 +Morocco,EUR,Full Day,42 +Morocco,EUR,Part Day,28 +Morocco,EUR,Overnight,129 +Morocco,EUR,Breakfast,-8.4 +Morocco,EUR,Lunch,-16.8 +Morocco,EUR,Dinner,-16.8 +Mozambique,EUR,Full Day,38 +Mozambique,EUR,Part Day,25 +Mozambique,EUR,Overnight,146 +Mozambique,EUR,Breakfast,-7.6 +Mozambique,EUR,Lunch,-15.2 +Mozambique,EUR,Dinner,-15.2 +Myanmar,EUR,Full Day,35 +Myanmar,EUR,Part Day,24 +Myanmar,EUR,Overnight,155 +Myanmar,EUR,Breakfast,-7 +Myanmar,EUR,Lunch,-14 +Myanmar,EUR,Dinner,-14 +Namibia,EUR,Full Day,23 +Namibia,EUR,Part Day,16 +Namibia,EUR,Overnight,77 +Namibia,EUR,Breakfast,-4.6 +Namibia,EUR,Lunch,-9.2 +Namibia,EUR,Dinner,-9.2 +Nepal,EUR,Full Day,28 +Nepal,EUR,Part Day,19 +Nepal,EUR,Overnight,86 +Nepal,EUR,Breakfast,-5.6 +Nepal,EUR,Lunch,-11.2 +Nepal,EUR,Dinner,-11.2 +Netherlands,EUR,Full Day,46 +Netherlands,EUR,Part Day,31 +Netherlands,EUR,Overnight,119 +Netherlands,EUR,Breakfast,-9.2 +Netherlands,EUR,Lunch,-18.4 +Netherlands,EUR,Dinner,-18.4 +New Zealand,EUR,Full Day,56 +New Zealand,EUR,Part Day,37 +New Zealand,EUR,Overnight,153 +New Zealand,EUR,Breakfast,-11.2 +New Zealand,EUR,Lunch,-22.4 +New Zealand,EUR,Dinner,-22.4 +Nicaragua,EUR,Full Day,36 +Nicaragua,EUR,Part Day,24 +Nicaragua,EUR,Overnight,81 +Nicaragua,EUR,Breakfast,-7.2 +Nicaragua,EUR,Lunch,-14.4 +Nicaragua,EUR,Dinner,-14.4 +Niger,EUR,Full Day,41 +Niger,EUR,Part Day,28 +Niger,EUR,Overnight,89 +Niger,EUR,Breakfast,-8.2 +Niger,EUR,Lunch,-16.4 +Niger,EUR,Dinner,-16.4 +Nigeria,EUR,Full Day,63 +Nigeria,EUR,Part Day,42 +Nigeria,EUR,Overnight,255 +Nigeria,EUR,Breakfast,-12.6 +Nigeria,EUR,Lunch,-25.2 +Nigeria,EUR,Dinner,-25.2 +Norway,EUR,Full Day,80 +Norway,EUR,Part Day,53 +Norway,EUR,Overnight,182 +Norway,EUR,Breakfast,-16 +Norway,EUR,Lunch,-32 +Norway,EUR,Dinner,-32 +Oman,EUR,Full Day,60 +Oman,EUR,Part Day,40 +Oman,EUR,Overnight,200 +Oman,EUR,Breakfast,-12 +Oman,EUR,Lunch,-24 +Oman,EUR,Dinner,-24 +Pakistan - Islamabad,EUR,Full Day,30 +Pakistan - Islamabad,EUR,Part Day,20 +Pakistan - Islamabad,EUR,Overnight,165 +Pakistan - Islamabad,EUR,Breakfast,-6 +Pakistan - Islamabad,EUR,Lunch,-12 +Pakistan - Islamabad,EUR,Dinner,-12 +Pakistan - for the rest,EUR,Full Day,27 +Pakistan - for the rest,EUR,Part Day,18 +Pakistan - for the rest,EUR,Overnight,68 +Pakistan - for the rest,EUR,Breakfast,-5.4 +Pakistan - for the rest,EUR,Lunch,-10.8 +Pakistan - for the rest,EUR,Dinner,-10.8 +Palau,EUR,Full Day,51 +Palau,EUR,Part Day,34 +Palau,EUR,Overnight,179 +Palau,EUR,Breakfast,-10.2 +Palau,EUR,Lunch,-20.4 +Palau,EUR,Dinner,-20.4 +Panama,EUR,Full Day,39 +Panama,EUR,Part Day,26 +Panama,EUR,Overnight,111 +Panama,EUR,Breakfast,-7.8 +Panama,EUR,Lunch,-15.6 +Panama,EUR,Dinner,-15.6 +Papua New Guinea,EUR,Full Day,60 +Papua New Guinea,EUR,Part Day,40 +Papua New Guinea,EUR,Overnight,234 +Papua New Guinea,EUR,Breakfast,-12 +Papua New Guinea,EUR,Lunch,-24 +Papua New Guinea,EUR,Dinner,-24 +Paraguay,EUR,Full Day,38 +Paraguay,EUR,Part Day,25 +Paraguay,EUR,Overnight,108 +Paraguay,EUR,Breakfast,-7.6 +Paraguay,EUR,Lunch,-15.2 +Paraguay,EUR,Dinner,-15.2 +Peru,EUR,Full Day,30 +Peru,EUR,Part Day,20 +Peru,EUR,Overnight,93 +Peru,EUR,Breakfast,-6 +Peru,EUR,Lunch,-12 +Peru,EUR,Dinner,-12 +Philippines,EUR,Full Day,33 +Philippines,EUR,Part Day,22 +Philippines,EUR,Overnight,116 +Philippines,EUR,Breakfast,-6.6 +Philippines,EUR,Lunch,-13.2 +Philippines,EUR,Dinner,-13.2 +Poland - Danzig,EUR,Full Day,30 +Poland - Danzig,EUR,Part Day,20 +Poland - Danzig,EUR,Overnight,84 +Poland - Danzig,EUR,Breakfast,-6 +Poland - Danzig,EUR,Lunch,-12 +Poland - Danzig,EUR,Dinner,-12 +Poland - Kraków,EUR,Full Day,27 +Poland - Kraków,EUR,Part Day,18 +Poland - Kraków,EUR,Overnight,86 +Poland - Kraków,EUR,Breakfast,-5.4 +Poland - Kraków,EUR,Lunch,-10.8 +Poland - Kraków,EUR,Dinner,-10.8 +Poland - Warsaw,EUR,Full Day,29 +Poland - Warsaw,EUR,Part Day,20 +Poland - Warsaw,EUR,Overnight,109 +Poland - Warsaw,EUR,Breakfast,-5.8 +Poland - Warsaw,EUR,Lunch,-11.6 +Poland - Warsaw,EUR,Dinner,-11.6 +Poland - Wrocław,EUR,Full Day,33 +Poland - Wrocław,EUR,Part Day,22 +Poland - Wrocław,EUR,Overnight,117 +Poland - Wrocław,EUR,Breakfast,-6.6 +Poland - Wrocław,EUR,Lunch,-13.2 +Poland - Wrocław,EUR,Dinner,-13.2 +Poland - for the rest,EUR,Full Day,29 +Poland - for the rest,EUR,Part Day,20 +Poland - for the rest,EUR,Overnight,60 +Poland - for the rest,EUR,Breakfast,-5.8 +Poland - for the rest,EUR,Lunch,-11.6 +Poland - for the rest,EUR,Dinner,-11.6 +Portugal,EUR,Full Day,36 +Portugal,EUR,Part Day,24 +Portugal,EUR,Overnight,102 +Portugal,EUR,Breakfast,-7.2 +Portugal,EUR,Lunch,-14.4 +Portugal,EUR,Dinner,-14.4 +Qatar,EUR,Full Day,56 +Qatar,EUR,Part Day,37 +Qatar,EUR,Overnight,170 +Qatar,EUR,Breakfast,-11.2 +Qatar,EUR,Lunch,-22.4 +Qatar,EUR,Dinner,-22.4 +Romania - Bucharest,EUR,Full Day,32 +Romania - Bucharest,EUR,Part Day,21 +Romania - Bucharest,EUR,Overnight,100 +Romania - Bucharest,EUR,Breakfast,-6.4 +Romania - Bucharest,EUR,Lunch,-12.8 +Romania - Bucharest,EUR,Dinner,-12.8 +Romania - for the rest,EUR,Full Day,26 +Romania - for the rest,EUR,Part Day,17 +Romania - for the rest,EUR,Overnight,62 +Romania - for the rest,EUR,Breakfast,-5.2 +Romania - for the rest,EUR,Lunch,-10.4 +Romania - for the rest,EUR,Dinner,-10.4 +Russia - Moscow,EUR,Full Day,30 +Russia - Moscow,EUR,Part Day,20 +Russia - Moscow,EUR,Overnight,110 +Russia - Moscow,EUR,Breakfast,-6 +Russia - Moscow,EUR,Lunch,-12 +Russia - Moscow,EUR,Dinner,-12 +Russia - St. Petersburg,EUR,Full Day,26 +Russia - St. Petersburg,EUR,Part Day,17 +Russia - St. Petersburg,EUR,Overnight,114 +Russia - St. Petersburg,EUR,Breakfast,-5.2 +Russia - St. Petersburg,EUR,Lunch,-10.4 +Russia - St. Petersburg,EUR,Dinner,-10.4 +Russia - Yekaterinburg,EUR,Full Day,28 +Russia - Yekaterinburg,EUR,Part Day,19 +Russia - Yekaterinburg,EUR,Overnight,84 +Russia - Yekaterinburg,EUR,Breakfast,-5.6 +Russia - Yekaterinburg,EUR,Lunch,-11.2 +Russia - Yekaterinburg,EUR,Dinner,-11.2 +Russia - for the rest,EUR,Full Day,24 +Russia - for the rest,EUR,Part Day,16 +Russia - for the rest,EUR,Overnight,58 +Russia - for the rest,EUR,Breakfast,-4.8 +Russia - for the rest,EUR,Lunch,-9.6 +Russia - for the rest,EUR,Dinner,-9.6 +Rwanda,EUR,Full Day,46 +Rwanda,EUR,Part Day,31 +Rwanda,EUR,Overnight,141 +Rwanda,EUR,Breakfast,-9.2 +Rwanda,EUR,Lunch,-18.4 +Rwanda,EUR,Dinner,-18.4 +Samoa,EUR,Full Day,29 +Samoa,EUR,Part Day,20 +Samoa,EUR,Overnight,85 +Samoa,EUR,Breakfast,-5.8 +Samoa,EUR,Lunch,-11.6 +Samoa,EUR,Dinner,-11.6 +San Marino,EUR,Full Day,34 +San Marino,EUR,Part Day,23 +San Marino,EUR,Overnight,75 +San Marino,EUR,Breakfast,-6.8 +San Marino,EUR,Lunch,-13.6 +San Marino,EUR,Dinner,-13.6 +São Tomé and Príncipe,EUR,Full Day,47 +São Tomé and Príncipe,EUR,Part Day,32 +São Tomé and Príncipe,EUR,Overnight,80 +São Tomé and Príncipe,EUR,Breakfast,-9.4 +São Tomé and Príncipe,EUR,Lunch,-18.8 +São Tomé and Príncipe,EUR,Dinner,-18.8 +Saudi Arabia - Jeddah,EUR,Full Day,38 +Saudi Arabia - Jeddah,EUR,Part Day,25 +Saudi Arabia - Jeddah,EUR,Overnight,234 +Saudi Arabia - Jeddah,EUR,Breakfast,-7.6 +Saudi Arabia - Jeddah,EUR,Lunch,-15.2 +Saudi Arabia - Jeddah,EUR,Dinner,-15.2 +Saudi Arabia - Riyadh,EUR,Full Day,48 +Saudi Arabia - Riyadh,EUR,Part Day,32 +Saudi Arabia - Riyadh,EUR,Overnight,179 +Saudi Arabia - Riyadh,EUR,Breakfast,-9.6 +Saudi Arabia - Riyadh,EUR,Lunch,-19.2 +Saudi Arabia - Riyadh,EUR,Dinner,-19.2 +Saudi Arabia - for the rest,EUR,Full Day,48 +Saudi Arabia - for the rest,EUR,Part Day,32 +Saudi Arabia - for the rest,EUR,Overnight,80 +Saudi Arabia - for the rest,EUR,Breakfast,-9.6 +Saudi Arabia - for the rest,EUR,Lunch,-19.2 +Saudi Arabia - for the rest,EUR,Dinner,-19.2 +Senegal,EUR,Full Day,45 +Senegal,EUR,Part Day,30 +Senegal,EUR,Overnight,128 +Senegal,EUR,Breakfast,-9 +Senegal,EUR,Lunch,-18 +Senegal,EUR,Dinner,-18 +Serbia,EUR,Full Day,20 +Serbia,EUR,Part Day,13 +Serbia,EUR,Overnight,74 +Serbia,EUR,Breakfast,-4 +Serbia,EUR,Lunch,-8 +Serbia,EUR,Dinner,-8 +Sierra Leone,EUR,Full Day,48 +Sierra Leone,EUR,Part Day,32 +Sierra Leone,EUR,Overnight,161 +Sierra Leone,EUR,Breakfast,-9.6 +Sierra Leone,EUR,Lunch,-19.2 +Sierra Leone,EUR,Dinner,-19.2 +Singapore,EUR,Full Day,54 +Singapore,EUR,Part Day,36 +Singapore,EUR,Overnight,197 +Singapore,EUR,Breakfast,-10.8 +Singapore,EUR,Lunch,-21.6 +Singapore,EUR,Dinner,-21.6 +Slovakia,EUR,Full Day,24 +Slovakia,EUR,Part Day,16 +Slovakia,EUR,Overnight,85 +Slovakia,EUR,Breakfast,-4.8 +Slovakia,EUR,Lunch,-9.6 +Slovakia,EUR,Dinner,-9.6 +Slovenia,EUR,Full Day,33 +Slovenia,EUR,Part Day,22 +Slovenia,EUR,Overnight,95 +Slovenia,EUR,Breakfast,-6.6 +Slovenia,EUR,Lunch,-13.2 +Slovenia,EUR,Dinner,-13.2 +South Africa - Cape Town,EUR,Full Day,27 +South Africa - Cape Town,EUR,Part Day,18 +South Africa - Cape Town,EUR,Overnight,112 +South Africa - Cape Town,EUR,Breakfast,-5.4 +South Africa - Cape Town,EUR,Lunch,-10.8 +South Africa - Cape Town,EUR,Dinner,-10.8 +South Africa - Johannesburg,EUR,Full Day,29 +South Africa - Johannesburg,EUR,Part Day,20 +South Africa - Johannesburg,EUR,Overnight,124 +South Africa - Johannesburg,EUR,Breakfast,-5.8 +South Africa - Johannesburg,EUR,Lunch,-11.6 +South Africa - Johannesburg,EUR,Dinner,-11.6 +Souh Africa - for the rest,EUR,Full Day,22 +Souh Africa - for the rest,EUR,Part Day,15 +Souh Africa - for the rest,EUR,Overnight,94 +Souh Africa - for the rest,EUR,Breakfast,-4.4 +Souh Africa - for the rest,EUR,Lunch,-8.8 +Souh Africa - for the rest,EUR,Dinner,-8.8 +South Sudan,EUR,Full Day,34 +South Sudan,EUR,Part Day,23 +South Sudan,EUR,Overnight,150 +South Sudan,EUR,Breakfast,-6.8 +South Sudan,EUR,Lunch,-13.6 +South Sudan,EUR,Dinner,-13.6 +Spain - Barcelona,EUR,Full Day,34 +Spain - Barcelona,EUR,Part Day,23 +Spain - Barcelona,EUR,Overnight,118 +Spain - Barcelona,EUR,Breakfast,-6.8 +Spain - Barcelona,EUR,Lunch,-13.6 +Spain - Barcelona,EUR,Dinner,-13.6 +Spain - Canary Islands,EUR,Full Day,40 +Spain - Canary Islands,EUR,Part Day,27 +Spain - Canary Islands,EUR,Overnight,115 +Spain - Canary Islands,EUR,Breakfast,-8 +Spain - Canary Islands,EUR,Lunch,-16 +Spain - Canary Islands,EUR,Dinner,-16 +Spain - Madrid,EUR,Full Day,40 +Spain - Madrid,EUR,Part Day,27 +Spain - Madrid,EUR,Overnight,118 +Spain - Madrid,EUR,Breakfast,-8 +Spain - Madrid,EUR,Lunch,-16 +Spain - Madrid,EUR,Dinner,-16 +Spain - Palma de Mallorca,EUR,Full Day,35 +Spain - Palma de Mallorca,EUR,Part Day,24 +Spain - Palma de Mallorca,EUR,Overnight,121 +Spain - Palma de Mallorca,EUR,Breakfast,-7 +Spain - Palma de Mallorca,EUR,Lunch,-14 +Spain - Palma de Mallorca,EUR,Dinner,-14 +Spain - for the rest,EUR,Full Day,34 +Spain - for the rest,EUR,Part Day,23 +Spain - for the rest,EUR,Overnight,115 +Spain - for the rest,EUR,Breakfast,-6.8 +Spain - for the rest,EUR,Lunch,-13.6 +Spain - for the rest,EUR,Dinner,-13.6 +Sri Lanka,EUR,Full Day,42 +Sri Lanka,EUR,Part Day,28 +Sri Lanka,EUR,Overnight,100 +Sri Lanka,EUR,Breakfast,-8.4 +Sri Lanka,EUR,Lunch,-16.8 +Sri Lanka,EUR,Dinner,-16.8 +St. Kitts and Nevis,EUR,Full Day,45 +St. Kitts and Nevis,EUR,Part Day,30 +St. Kitts and Nevis,EUR,Overnight,177 +St. Kitts and Nevis,EUR,Breakfast,-9 +St. Kitts and Nevis,EUR,Lunch,-18 +St. Kitts and Nevis,EUR,Dinner,-18 +St. Lucia,EUR,Full Day,45 +St. Lucia,EUR,Part Day,30 +St. Lucia,EUR,Overnight,177 +St. Lucia,EUR,Breakfast,-9 +St. Lucia,EUR,Lunch,-18 +St. Lucia,EUR,Dinner,-18 +St. Vincent and the Grenadines,EUR,Full Day,45 +St. Vincent and the Grenadines,EUR,Part Day,30 +St. Vincent and the Grenadines,EUR,Overnight,177 +St. Vincent and the Grenadines,EUR,Breakfast,-9 +St. Vincent and the Grenadines,EUR,Lunch,-18 +St. Vincent and the Grenadines,EUR,Dinner,-18 +Sudan,EUR,Full Day,35 +Sudan,EUR,Part Day,24 +Sudan,EUR,Overnight,115 +Sudan,EUR,Breakfast,-7 +Sudan,EUR,Lunch,-14 +Sudan,EUR,Dinner,-14 +Suriname,EUR,Full Day,45 +Suriname,EUR,Part Day,30 +Suriname,EUR,Overnight,177 +Suriname,EUR,Breakfast,-9 +Suriname,EUR,Lunch,-18 +Suriname,EUR,Dinner,-18 +Sweden,EUR,Full Day,50 +Sweden,EUR,Part Day,33 +Sweden,EUR,Overnight,168 +Sweden,EUR,Breakfast,-10 +Sweden,EUR,Lunch,-20 +Sweden,EUR,Dinner,-20 +Switzerland - Geneva,EUR,Full Day,64 +Switzerland - Geneva,EUR,Part Day,43 +Switzerland - Geneva,EUR,Overnight,195 +Switzerland - Geneva,EUR,Breakfast,-12.8 +Switzerland - Geneva,EUR,Lunch,-25.6 +Switzerland - Geneva,EUR,Dinner,-25.6 +Switzerland - for the rest,EUR,Full Day,62 +Switzerland - for the rest,EUR,Part Day,41 +Switzerland - for the rest,EUR,Overnight,169 +Switzerland - for the rest,EUR,Breakfast,-12.4 +Switzerland - for the rest,EUR,Lunch,-24.8 +Switzerland - for the rest,EUR,Dinner,-24.8 +Syria,EUR,Full Day,38 +Syria,EUR,Part Day,25 +Syria,EUR,Overnight,140 +Syria,EUR,Breakfast,-7.6 +Syria,EUR,Lunch,-15.2 +Syria,EUR,Dinner,-15.2 +Taiwan,EUR,Full Day,51 +Taiwan,EUR,Part Day,34 +Taiwan,EUR,Overnight,126 +Taiwan,EUR,Breakfast,-10.2 +Taiwan,EUR,Lunch,-20.4 +Taiwan,EUR,Dinner,-20.4 +Tajikistan,EUR,Full Day,27 +Tajikistan,EUR,Part Day,18 +Tajikistan,EUR,Overnight,118 +Tajikistan,EUR,Breakfast,-5.4 +Tajikistan,EUR,Lunch,-10.8 +Tajikistan,EUR,Dinner,-10.8 +Tanzania,EUR,Full Day,47 +Tanzania,EUR,Part Day,32 +Tanzania,EUR,Overnight,201 +Tanzania,EUR,Breakfast,-9.4 +Tanzania,EUR,Lunch,-18.8 +Tanzania,EUR,Dinner,-18.8 +Thailand,EUR,Full Day,38 +Thailand,EUR,Part Day,25 +Thailand,EUR,Overnight,110 +Thailand,EUR,Breakfast,-7.6 +Thailand,EUR,Lunch,-15.2 +Thailand,EUR,Dinner,-15.2 +Togo,EUR,Full Day,35 +Togo,EUR,Part Day,24 +Togo,EUR,Overnight,108 +Togo,EUR,Breakfast,-7 +Togo,EUR,Lunch,-14 +Togo,EUR,Dinner,-14 +Tonga,EUR,Full Day,39 +Tonga,EUR,Part Day,26 +Tonga,EUR,Overnight,94 +Tonga,EUR,Breakfast,-7.8 +Tonga,EUR,Lunch,-15.6 +Tonga,EUR,Dinner,-15.6 +Trinidad and Tobago,EUR,Full Day,45 +Trinidad and Tobago,EUR,Part Day,30 +Trinidad and Tobago,EUR,Overnight,177 +Trinidad and Tobago,EUR,Breakfast,-9 +Trinidad and Tobago,EUR,Lunch,-18 +Trinidad and Tobago,EUR,Dinner,-18 +Tunisia,EUR,Full Day,40 +Tunisia,EUR,Part Day,27 +Tunisia,EUR,Overnight,115 +Tunisia,EUR,Breakfast,-8 +Tunisia,EUR,Lunch,-16 +Tunisia,EUR,Dinner,-16 +Turkey - Istanbul,EUR,Full Day,35 +Turkey - Istanbul,EUR,Part Day,24 +Turkey - Istanbul,EUR,Overnight,104 +Turkey - Istanbul,EUR,Breakfast,-7 +Turkey - Istanbul,EUR,Lunch,-14 +Turkey - Istanbul,EUR,Dinner,-14 +Turkey - Izmir,EUR,Full Day,42 +Turkey - Izmir,EUR,Part Day,28 +Turkey - Izmir,EUR,Overnight,80 +Turkey - Izmir,EUR,Breakfast,-8.4 +Turkey - Izmir,EUR,Lunch,-16.8 +Turkey - Izmir,EUR,Dinner,-16.8 +Turkey - for the rest,EUR,Full Day,40 +Turkey - for the rest,EUR,Part Day,27 +Turkey - for the rest,EUR,Overnight,78 +Turkey - for the rest,EUR,Breakfast,-8 +Turkey - for the rest,EUR,Lunch,-16 +Turkey - for the rest,EUR,Dinner,-16 +Turkmenistan,EUR,Full Day,33 +Turkmenistan,EUR,Part Day,22 +Turkmenistan,EUR,Overnight,108 +Turkmenistan,EUR,Breakfast,-6.6 +Turkmenistan,EUR,Lunch,-13.2 +Turkmenistan,EUR,Dinner,-13.2 +Uganda,EUR,Full Day,35 +Uganda,EUR,Part Day,24 +Uganda,EUR,Overnight,129 +Uganda,EUR,Breakfast,-7 +Uganda,EUR,Lunch,-14 +Uganda,EUR,Dinner,-14 +Ukraine,EUR,Full Day,32 +Ukraine,EUR,Part Day,21 +Ukraine,EUR,Overnight,98 +Ukraine,EUR,Breakfast,-6.4 +Ukraine,EUR,Lunch,-12.8 +Ukraine,EUR,Dinner,-12.8 +United Arab Emirates,EUR,Full Day,45 +United Arab Emirates,EUR,Part Day,30 +United Arab Emirates,EUR,Overnight,155 +United Arab Emirates,EUR,Breakfast,-9 +United Arab Emirates,EUR,Lunch,-18 +United Arab Emirates,EUR,Dinner,-18 +United Kingdom of Great Britain and Ireland,EUR,Full Day, +United Kingdom of Great Britain and Ireland,EUR,Part Day, +United Kingdom of Great Britain and Ireland,EUR,Overnight, +United Kingdom of Great Britain and Ireland,EUR,Breakfast,0 +United Kingdom of Great Britain and Ireland,EUR,Lunch,0 +United Kingdom of Great Britain and Ireland,EUR,Dinner,0 +United Kingdom - London,EUR,Full Day,62 +United Kingdom - London,EUR,Part Day,41 +United Kingdom - London,EUR,Overnight,224 +United Kingdom - London,EUR,Breakfast,-12.4 +United Kingdom - London,EUR,Lunch,-24.8 +United Kingdom - London,EUR,Dinner,-24.8 +United Kingdom - for the rest,EUR,Full Day,45 +United Kingdom - for the rest,EUR,Part Day,30 +United Kingdom - for the rest,EUR,Overnight,115 +United Kingdom - for the rest,EUR,Breakfast,-9 +United Kingdom - for the rest,EUR,Lunch,-18 +United Kingdom - for the rest,EUR,Dinner,-18 +United States of America - Atlanta,EUR,Full Day,62 +United States of America - Atlanta,EUR,Part Day,41 +United States of America - Atlanta,EUR,Overnight,175 +United States of America - Atlanta,EUR,Breakfast,-12.4 +United States of America - Atlanta,EUR,Lunch,-24.8 +United States of America - Atlanta,EUR,Dinner,-24.8 +United States of America - Boston,EUR,Full Day,58 +United States of America - Boston,EUR,Part Day,39 +United States of America - Boston,EUR,Overnight,265 +United States of America - Boston,EUR,Breakfast,-11.6 +United States of America - Boston,EUR,Lunch,-23.2 +United States of America - Boston,EUR,Dinner,-23.2 +United States of America - Chicago,EUR,Full Day,54 +United States of America - Chicago,EUR,Part Day,36 +United States of America - Chicago,EUR,Overnight,209 +United States of America - Chicago,EUR,Breakfast,-10.8 +United States of America - Chicago,EUR,Lunch,-21.6 +United States of America - Chicago,EUR,Dinner,-21.6 +United States of America - Houston,EUR,Full Day,63 +United States of America - Houston,EUR,Part Day,42 +United States of America - Houston,EUR,Overnight,138 +United States of America - Houston,EUR,Breakfast,-12.6 +United States of America - Houston,EUR,Lunch,-25.2 +United States of America - Houston,EUR,Dinner,-25.2 +United States of America - Los Angeles,EUR,Full Day,56 +United States of America - Los Angeles,EUR,Part Day,37 +United States of America - Los Angeles,EUR,Overnight,274 +United States of America - Los Angeles,EUR,Breakfast,-11.2 +United States of America - Los Angeles,EUR,Lunch,-22.4 +United States of America - Los Angeles,EUR,Dinner,-22.4 +United States of America - Miami,EUR,Full Day,64 +United States of America - Miami,EUR,Part Day,43 +United States of America - Miami,EUR,Overnight,151 +United States of America - Miami,EUR,Breakfast,-12.8 +United States of America - Miami,EUR,Lunch,-25.6 +United States of America - Miami,EUR,Dinner,-25.6 +United States of America - New York,EUR,Full Day,58 +United States of America - New York,EUR,Part Day,39 +United States of America - New York,EUR,Overnight,282 +United States of America - New York,EUR,Breakfast,-11.6 +United States of America - New York,EUR,Lunch,-23.2 +United States of America - New York,EUR,Dinner,-23.2 +United States of America - San Francisco,EUR,Full Day,51 +United States of America - San Francisco,EUR,Part Day,34 +United States of America - San Francisco,EUR,Overnight,314 +United States of America - San Francisco,EUR,Breakfast,-10.2 +United States of America - San Francisco,EUR,Lunch,-20.4 +United States of America - San Francisco,EUR,Dinner,-20.4 +United States of America - Washington D.C.,EUR,Full Day,62 +United States of America - Washington D.C.,EUR,Part Day,41 +United States of America - Washington D.C.,EUR,Overnight,276 +United States of America - Washington D.C.,EUR,Breakfast,-12.4 +United States of America - Washington D.C.,EUR,Lunch,-24.8 +United States of America - Washington D.C.,EUR,Dinner,-24.8 +United States of America - for the rest,EUR,Full Day,51 +United States of America - for the rest,EUR,Part Day,34 +United States of America - for the rest,EUR,Overnight,138 +United States of America - for the rest,EUR,Breakfast,-10.2 +United States of America - for the rest,EUR,Lunch,-20.4 +United States of America - for the rest,EUR,Dinner,-20.4 +Uruguay,EUR,Full Day,44 +Uruguay,EUR,Part Day,29 +Uruguay,EUR,Overnight,109 +Uruguay,EUR,Breakfast,-8.8 +Uruguay,EUR,Lunch,-17.6 +Uruguay,EUR,Dinner,-17.6 +Uzbekistan,EUR,Full Day,34 +Uzbekistan,EUR,Part Day,23 +Uzbekistan,EUR,Overnight,123 +Uzbekistan,EUR,Breakfast,-6.8 +Uzbekistan,EUR,Lunch,-13.6 +Uzbekistan,EUR,Dinner,-13.6 +Vatican City,EUR,Full Day,52 +Vatican City,EUR,Part Day,35 +Vatican City,EUR,Overnight,160 +Vatican City,EUR,Breakfast,-10.4 +Vatican City,EUR,Lunch,-20.8 +Vatican City,EUR,Dinner,-20.8 +Venezuela,EUR,Full Day,69 +Venezuela,EUR,Part Day,46 +Venezuela,EUR,Overnight,127 +Venezuela,EUR,Breakfast,-13.8 +Venezuela,EUR,Lunch,-27.6 +Venezuela,EUR,Dinner,-27.6 +Vietnam,EUR,Full Day,41 +Vietnam,EUR,Part Day,28 +Vietnam,EUR,Overnight,86 +Vietnam,EUR,Breakfast,-8.2 +Vietnam,EUR,Lunch,-16.4 +Vietnam,EUR,Dinner,-16.4 +Yemen,EUR,Full Day,24 +Yemen,EUR,Part Day,16 +Yemen,EUR,Overnight,95 +Yemen,EUR,Breakfast,-4.8 +Yemen,EUR,Lunch,-9.6 +Yemen,EUR,Dinner,-9.6 +Zambia,EUR,Full Day,36 +Zambia,EUR,Part Day,24 +Zambia,EUR,Overnight,130 +Zambia,EUR,Breakfast,-7.2 +Zambia,EUR,Lunch,-14.4 +Zambia,EUR,Dinner,-14.4 +Zimbabwe,EUR,Full Day,45 +Zimbabwe,EUR,Part Day,30 +Zimbabwe,EUR,Overnight,140 +Zimbabwe,EUR,Breakfast,-9 +Zimbabwe,EUR,Lunch,-18 +Zimbabwe,EUR,Dinner,-18 \ No newline at end of file diff --git a/docs/assets/Files/Independent+with+GL+codes+format.csv b/docs/assets/Files/Independent+with+GL+codes+format.csv new file mode 100644 index 000000000000..1bcda47c1fb3 --- /dev/null +++ b/docs/assets/Files/Independent+with+GL+codes+format.csv @@ -0,0 +1 @@ +Department,Department GL,Region,Region GL,Project,Project GL Accounting,1000,North America,100,Project 1,10 Marketing,2000,South America,200,Project 2,20 Sales,3000,Africa,300,Project 3,30 HR,4000,Europe,400,Project 4,40 Engineering,5000,Asia,500,Project 5,50 Ops,6000,Australia,600,Project 6,60 \ No newline at end of file diff --git a/docs/assets/Files/Independent+without+GL+codes+format.csv b/docs/assets/Files/Independent+without+GL+codes+format.csv new file mode 100644 index 000000000000..a8a4b58515b6 --- /dev/null +++ b/docs/assets/Files/Independent+without+GL+codes+format.csv @@ -0,0 +1 @@ +Department,Region,Project Accounting,North America,Project 1 Marketing,South America,Project 2 Sales,Africa,Project 3 HR,Europe,Project 4 Engineering,Asia,Project 5 Ops,Australia,Project 6 \ No newline at end of file diff --git a/docs/assets/Files/South-Africa-per-diem.csv b/docs/assets/Files/South-Africa-per-diem.csv new file mode 100644 index 000000000000..d8ed328edec6 --- /dev/null +++ b/docs/assets/Files/South-Africa-per-diem.csv @@ -0,0 +1,186 @@ +rateID,Destination,Subrate,Amount,Currency +5e6618c88c782,Albania,International,100,EUR +5e6618c88c788,Algeria,International,110,EUR +5e6618c88c78a,Angola,International,303,USD +5e6618c88c78b,Antigua and Barbuda,International,220,USD +5e6618c88c78d,Argentina,International,133,USD +5e6618c88c78e,Armenia,International,220,USD +5e6618c88c78f,Australia,International,230,AUD +5e6618c88c790,Austria,International,131,EUR +5e6618c88c792,Bahamas,International,191,USD +5e6618c88c793,Bahrain,International,36,BHD +5e6618c88c794,Bangladesh,International,79,USD +5e6618c88c795,Barbados,International,202,USD +5e6618c88c796,Belarus,International,62,EUR +5e6618c88c798,Belgium,International,146,EUR +5e6618c88c799,Belize,International,152,USD +5e6618c88c79a,Benin,International,111,EUR +5e6618c88c79b,Bolivia,International,78,USD +5e6618c88c79c,Bosnia-Herzegovina,International,75,EUR +5e6618c88c79d,Botswana,International,826,BWP +5e6618c88c79e,Brazil,International,409,BRL +5e6618c88c79f,Brunei,International,88,USD +5e6618c88c7a0,Bulgaria,International,91,EUR +5e6618c88c7a1,Burkina Faso,International,"58,790.00",XAF +5e6618c88c7a3,Burundi,International,73,EUR +5e6618c88c7a4,Cambodia,International,99,USD +5e6618c88c7a5,Cameroon,International,120,EUR +5e6618c88c7a6,Cape Verde Islands,International,65,EUR +5e6618c88c7a7,Central African Republic,International,94,EUR +5e6618c88c7a9,Chad,International,121,EUR +5e6618c88c7aa,Chile,International,106,USD +5e6618c88c7af,China (People's Republic),International,127,USD +5e6618c88c7b0,Colombia,International,94,USD +5e6618c88c7b1,Comoro Island,International,122,EUR +5e6618c88c7b2,Cook Islands,International,211,NZD +5e6618c88c7b3,Costa Rica,International,116,USD +5e6618c88c7b4,Cote D'Ivoire,International,119,EUR +5e6618c88c7b6,Croatia,International,99,EUR +5e6618c88c7b7,Cuba,International,114,USD +5e6618c88c7b8,Cyprus,International,117,EUR +5e6618c88c7b9,Czech Republic,International,90,EUR +5e6618c88c7ba,Democratic Republic of Congo,International,164,USD +5e6618c88c7bb,Denmark,International,"2,328.00",DKK +5e6618c88c7bc,Djibouti,International,99,USD +5e6618c88c7bd,Dominican Republic,International,99,USD +5e6618c88c7be,Ecuador,International,163,USD +5e6618c88c7bf,Egypt,International,873,USD +5e6618c88c7c0,El Salvador,International,98,USD +5e6618c88c7c1,Equatorial Guinea,International,166,EUR +5e6618c88c7c2,Eritrea,International,109,USD +5e6618c88c7c3,Estonia,International,92,EUR +5e6618c88c7c4,Ethiopia,International,95,USD +5e6618c88c7c5,Fiji,International,102,USD +5e6618c88c7c6,Finland,International,171,EUR +5e6618c88c7c7,France,International,129,EUR +5e6618c88c7c8,Gabon,International,160,EUR +5e6618c88c7c9,Gambia,International,74,EUR +5e6618c88c7ca,Georgia,International,95,USD +5e6618c88c7cb,Germany,International,125,EUR +5e6618c88c7cc,Ghana,International,130,USD +5e6618c88c7cd,Greece,International,138,EUR +5e6618c88c7ce,Grenada,International,151,USD +5e6618c88c7cf,Guatemala,International,114,USD +5e6618c88c7d0,Guinea,International,78,EUR +5e6618c88c7d1,Guinea Bissau,International,59,EUR +5e6618c88c7d2,Guyana,International,118,USD +5e6618c88c7d3,Haiti,International,109,USD +5e6618c88c7d4,Honduras,International,186,USD +5e6618c88c7d5,Hong Kong,International,"1,000.00",HKD +5e6618c88c7d6,Hungary,International,92,EUR +5e6618c88c7d7,Iceland,International,"25,466.00",ISK +5e6618c88c7d8,India,International,"5,852.00",INR +5e6618c88c7d9,Indonesia,International,86,USD +5e6618c88c7da,Iran,International,120,USD +5e6618c88c7db,Iraq,International,125,USD +5e6618c88c7dc,Ireland,International,139,EUR +5e6618c88c7dd,Israel,International,209,USD +5e6618c88c7e1,Italy,International,125,EUR +5e6618c88c7e3,Jamaica,International,151,USD +5e6618c88c7e4,Japan,International,"16,275.00",JPY +5e6618c88c7e5,Jordan,International,201,USD +5e6618c88c7e6,Kazakhstan,International,100,USD +5e6618c88c7e7,Kenya,International,138,USD +5e6618c88c7e8,Kiribati,International,233,AUD +5e6618c88c7e9,Kuwait (State of),International,51,KWD +5e6618c88c7ea,Kyrgyzstan,International,172,USD +5e6618c88c7eb,Laos,International,92,USD +5e6618c88c7ec,Latvia,International,150,USD +5e6618c88c7ed,Lebanon,International,158,USD +5e6618c88c7ee,Lesotho,International,750,ZAR +5e6618c88c7ef,Liberia,International,112,USD +5e6618c88c7f0,Libya,International,120,USD +5e6618c88c7f1,Lithuania,International,154,EUR +5e6618c88c7f2,Macedonia (Former Yugoslav),International,100,EUR +5e6618c88c7f3,Madagascar,International,58,EUR +5e6618c88c7f4,Malawi,International,"31,254.00",MWK +5e6618c88c7f5,Malaysia,International,382,MYR +5e6618c88c7f6,Maldives,International,202,USD +5e6618c88c7f7,Mali,International,178,EUR +5e6618c88c7f8,Malta,International,132,EUR +5e6618c88c7f9,Marshall Islands,International,255,USD +5e6618c88c7fa,Mauritania,International,97,EUR +5e6618c88c7fb,Mauritius,International,114,USD +5e6618c88c7fc,Mexico,International,"1,313.00",MXN +5e6618c88c7fd,Moldova,International,117,USD +5e6618c88c7fe,Mongolia,International,69,USD +5e6618c88c7ff,Montenegro,International,94,EUR +5e6618c88c800,Morocco,International,"1,081.00",AED +5e6618c88c801,Mozambique,International,101,USD +5e6618c88c802,Myanmar,International,123,USD +5e6618c88c803,Namibia,International,950,ZAR +5e6618c88c804,Nauru,International,278,AUD +5e6618c88c805,Nepal,International,64,USD +5e6618c88c806,Netherlands,International,122,EUR +5e6618c88c807,New Zealand,International,206,NZD +5e6618c88c808,Nicaragua,International,90,USD +5e6618c88c809,Niger,International,75,EUR +5e6618c88c80a,Nigeria,International,242,USD +5e6618c88c80b,Niue,International,252,NZD +5e6618c88c80c,Norway,International,"1,760.00",NOK +5e6618c88c80d,Oman,International,77,OMR +5e6618c88c80e,Pakistan,International,"6,235.00",PKR +5e6618c88c80f,Palau,International,252,USD +5e6618c88c810,Palestine,International,147,USD +5e6618c88c811,Panama,International,105,USD +5e6618c88c812,Papa New Guinea,International,285,PGK +5e6618c88c813,Paraguay,International,76,USD +5e6618c88c815,Peru,International,139,USD +5e6618c88c816,Philippines,International,122,USD +5e6618c88c817,Poland,International,88,EUR +5e6618c88c818,Portugal,International,87,EUR +5e6618c88c819,Puerto Rico,International,215,USD +5e6618c88c81a,Qatar,International,715,QAR +5e6618c88c81b,Republic of Congo,International,149,EUR +5e6618c88c81c,Reunion,International,164,EUR +5e6618c88c81d,Romania,International,83,EUR +5e6618c88c81e,Russia,International,330,EUR +5e6618c88c81f,Rwanda,International,102,USD +5e6618c88c823,Samoa,International,193,WST +5e6618c88c825,Sao Tome & Principe,International,160,EUR +5e6618c88c826,Saudi Arabia,International,512,SAR +5e6618c88c827,Senegal,International,113,EUR +5e6618c88c829,Serbia,International,83,EUR +5e6618c88c82a,Seychelles,International,132,EUR +5e6618c88c82c,Sierra Leone,International,90,USD +5e6618c88c83b,Slovakia,International,102,EUR +5e6618c88c83c,Slovenia,International,106,EUR +5e6618c88c83d,Solomon Islands,International,"1,107.00",SBD +5e6618c88c83e,South Korea Republic,International,"187,735.00",KRW +5e6618c88c840,South Sudan,International,146,USD +5e6618c88c841,Spain,International,112,EUR +5e6618c88c842,Sri Lanka,International,100,USD +5e6618c88c843,St. Kitts & Nevis,International,227,USD +5e6618c88c844,St. Lucia,International,215,USD +5e6618c88c845,St. Vincent & The Grenadines,International,187,USD +5e6618c88c846,Sudan,International,200,USD +5e6618c88c847,Suriname,International,107,USD +5e6618c88c848,Swaziland,International,"1,367.00",ZAR +5e6618c88c849,Sweden,International,"1,317.00",SEK +5e6618c88c84a,Switzerland,International,201,CHF +5e6618c88c84b,Syria,International,185,USD +5e6618c88c84c,Taiwan,International,"3,505.00",TWD +5e6618c88c84d,Tajikistan,International,97,USD +5e6618c88c84e,Tanzania,International,129,USD +5e6618c88c84f,Togo,International,"64,214.00",XAF +5e6618c88c850,Tonga,International,251,TOP +5e6618c88c851,Trinidad & Tobago,International,213,USD +5e6618c88c852,Tunisia,International,198,TND +5e6618c88c853,Turkey,International,101,EUR +5e6618c88c854,Turkmenistan,International,125,USD +5e6618c88c855,Tuvalu,International,339,AUD +5e6618c88c856,USA,International,215,USD +5e6618c88c857,Uganda,International,111,USD +5e6618c88c858,Ukraine,International,131,EUR +5e6618c88c859,Unit Kingdom - Fiber Lean,International,40,GBP +5e6618c88c85a,United Arab Emirates,International,699,AED +5e6618c88c85e,United Kingdom,International,102,GBP +5e6618c88c860,Uruguay,International,133,USD +5e6618c88c861,Uzbekistan,International,80,EUR +5e6618c88c863,Vanuatu,International,166,USD +5e6618c88c864,Venezuela,International,294,USD +5e6618c88c865,Vietnam,International,91,USD +5e6618c88c866,Yemen,International,94,USD +5e6618c88c867,Zambia,International,119,USD +5e6618c88c868,Zimbabwe,International,123,USD +5e6618c88c8a4,South Africa,Local,452,ZAR \ No newline at end of file diff --git a/docs/assets/Files/Sweden-per-diem.csv b/docs/assets/Files/Sweden-per-diem.csv new file mode 100644 index 000000000000..d20c0ac8e991 --- /dev/null +++ b/docs/assets/Files/Sweden-per-diem.csv @@ -0,0 +1,2037 @@ +Destination,Currency,Subrate,Amount +Albanien (2018),SEK,Normalbelopp,230 +Albanien (2018),SEK,Breakfast,-34.5 +Albanien (2018),SEK,Lunch,-80.5 +Albanien (2018),SEK,Dinner,-80.5 +Albanien (2019),SEK,Normalbelopp,242 +Albanien (2019),SEK,Breakfast,-36.3 +Albanien (2019),SEK,Lunch,-84.7 +Albanien (2019),SEK,Dinner,-84.7 +Albanien (2020),SEK,Normalbelopp,254 +Albanien (2020),SEK,Breakfast,-38.1 +Albanien (2020),SEK,Lunch,-88.9 +Albanien (2020),SEK,Dinner,-88.9 +Algeriet (2018),SEK,Normalbelopp,335 +Algeriet (2018),SEK,Breakfast,-50.25 +Algeriet (2018),SEK,Lunch,-117.25 +Algeriet (2018),SEK,Dinner,-117.25 +Algeriet (2019),SEK,Normalbelopp,362 +Algeriet (2019),SEK,Breakfast,-54.3 +Algeriet (2019),SEK,Lunch,-126.7 +Algeriet (2019),SEK,Dinner,-126.7 +Algeriet (2020),SEK,Normalbelopp,378 +Algeriet (2020),SEK,Breakfast,-56.7 +Algeriet (2020),SEK,Lunch,-132.3 +Algeriet (2020),SEK,Dinner,-132.3 +Angola (2018),SEK,Normalbelopp,937 +Angola (2018),SEK,Breakfast,-140.55 +Angola (2018),SEK,Lunch,-327.95 +Angola (2018),SEK,Dinner,-327.95 +Angola (2019),SEK,Normalbelopp,567 +Angola (2019),SEK,Breakfast,-85.05 +Angola (2019),SEK,Lunch,-198.45 +Angola (2019),SEK,Dinner,-198.45 +Angola (2020),SEK,Normalbelopp,346 +Angola (2020),SEK,Breakfast,-51.9 +Angola (2020),SEK,Lunch,-121.1 +Angola (2020),SEK,Dinner,-121.1 +Antigua och Barbuda (2018),SEK,Normalbelopp,613 +Antigua och Barbuda (2018),SEK,Breakfast,-91.95 +Antigua och Barbuda (2018),SEK,Lunch,-214.55 +Antigua och Barbuda (2018),SEK,Dinner,-214.55 +Antigua och Barbuda (2019),SEK,Normalbelopp,670 +Antigua och Barbuda (2019),SEK,Breakfast,-100.5 +Antigua och Barbuda (2019),SEK,Lunch,-234.5 +Antigua och Barbuda (2019),SEK,Dinner,-234.5 +Antigua och Barbuda (2020),SEK,Normalbelopp,697 +Antigua och Barbuda (2020),SEK,Breakfast,-104.55 +Antigua och Barbuda (2020),SEK,Lunch,-243.95 +Antigua och Barbuda (2020),SEK,Dinner,-243.95 +Argentina (2018),SEK,Normalbelopp,454 +Argentina (2018),SEK,Breakfast,-68.1 +Argentina (2018),SEK,Lunch,-158.9 +Argentina (2018),SEK,Dinner,-158.9 +Argentina (2019),SEK,Normalbelopp,276 +Argentina (2019),SEK,Breakfast,-41.4 +Argentina (2019),SEK,Lunch,-96.6 +Argentina (2019),SEK,Dinner,-96.6 +Argentina (2020),SEK,Normalbelopp,240 +Argentina (2020),SEK,Breakfast,-36 +Argentina (2020),SEK,Lunch,-84 +Argentina (2020),SEK,Dinner,-84 +Armenien (2018),SEK,Normalbelopp,313 +Armenien (2018),SEK,Breakfast,-46.95 +Armenien (2018),SEK,Lunch,-109.55 +Armenien (2018),SEK,Dinner,-109.55 +Armenien (2019),SEK,Normalbelopp,329 +Armenien (2019),SEK,Breakfast,-49.35 +Armenien (2019),SEK,Lunch,-115.15 +Armenien (2019),SEK,Dinner,-115.15 +Armenien (2020),SEK,Normalbelopp,358 +Armenien (2020),SEK,Breakfast,-53.7 +Armenien (2020),SEK,Lunch,-125.3 +Armenien (2020),SEK,Dinner,-125.3 +Australien (2018),SEK,Normalbelopp,683 +Australien (2018),SEK,Breakfast,-102.45 +Australien (2018),SEK,Lunch,-239.05 +Australien (2018),SEK,Dinner,-239.05 +Australien (2019),SEK,Normalbelopp,685 +Australien (2019),SEK,Breakfast,-102.75 +Australien (2019),SEK,Lunch,-239.75 +Australien (2019),SEK,Dinner,-239.75 +Australien (2020),SEK,Normalbelopp,697 +Australien (2020),SEK,Breakfast,-104.55 +Australien (2020),SEK,Lunch,-243.95 +Australien (2020),SEK,Dinner,-243.95 +Azerbajdzjan (2018),SEK,Normalbelopp,322 +Azerbajdzjan (2018),SEK,Breakfast,-48.3 +Azerbajdzjan (2018),SEK,Lunch,-112.7 +Azerbajdzjan (2018),SEK,Dinner,-112.7 +Azerbajdzjan (2019),SEK,Normalbelopp,345 +Azerbajdzjan (2019),SEK,Breakfast,-51.75 +Azerbajdzjan (2019),SEK,Lunch,-120.75 +Azerbajdzjan (2019),SEK,Dinner,-120.75 +Azerbajdzjan (2020),SEK,Normalbelopp,359 +Azerbajdzjan (2020),SEK,Breakfast,-53.85 +Azerbajdzjan (2020),SEK,Lunch,-125.65 +Azerbajdzjan (2020),SEK,Dinner,-125.65 +Bahamas (2018),SEK,Normalbelopp,797 +Bahamas (2018),SEK,Breakfast,-119.55 +Bahamas (2018),SEK,Lunch,-278.95 +Bahamas (2018),SEK,Dinner,-278.95 +Bahamas (2019),SEK,Normalbelopp,878 +Bahamas (2019),SEK,Breakfast,-131.7 +Bahamas (2019),SEK,Lunch,-307.3 +Bahamas (2019),SEK,Dinner,-307.3 +Bahamas (2020),SEK,Normalbelopp,953 +Bahamas (2020),SEK,Breakfast,-142.95 +Bahamas (2020),SEK,Lunch,-333.55 +Bahamas (2020),SEK,Dinner,-333.55 +Bahrain (2018),SEK,Normalbelopp,581 +Bahrain (2018),SEK,Breakfast,-87.15 +Bahrain (2018),SEK,Lunch,-203.35 +Bahrain (2018),SEK,Dinner,-203.35 +Bahrain (2019),SEK,Normalbelopp,661 +Bahrain (2019),SEK,Breakfast,-99.15 +Bahrain (2019),SEK,Lunch,-231.35 +Bahrain (2019),SEK,Dinner,-231.35 +Bahrain (2020),SEK,Normalbelopp,696 +Bahrain (2020),SEK,Breakfast,-104.4 +Bahrain (2020),SEK,Lunch,-243.6 +Bahrain (2020),SEK,Dinner,-243.6 +Bangladesh (2018),SEK,Normalbelopp,389 +Bangladesh (2018),SEK,Breakfast,-58.35 +Bangladesh (2018),SEK,Lunch,-136.15 +Bangladesh (2018),SEK,Dinner,-136.15 +Bangladesh (2019),SEK,Normalbelopp,429 +Bangladesh (2019),SEK,Breakfast,-64.35 +Bangladesh (2019),SEK,Lunch,-150.15 +Bangladesh (2019),SEK,Dinner,-150.15 +Bangladesh (2020),SEK,Normalbelopp,457 +Bangladesh (2020),SEK,Breakfast,-68.55 +Bangladesh (2020),SEK,Lunch,-159.95 +Bangladesh (2020),SEK,Dinner,-159.95 +Barbados (2018),SEK,Normalbelopp,738 +Barbados (2018),SEK,Breakfast,-110.7 +Barbados (2018),SEK,Lunch,-258.3 +Barbados (2018),SEK,Dinner,-258.3 +Barbados (2019),SEK,Normalbelopp,818 +Barbados (2019),SEK,Breakfast,-122.7 +Barbados (2019),SEK,Lunch,-286.3 +Barbados (2019),SEK,Dinner,-286.3 +Barbados (2020),SEK,Normalbelopp,893 +Barbados (2020),SEK,Breakfast,-133.95 +Barbados (2020),SEK,Lunch,-312.55 +Barbados (2020),SEK,Dinner,-312.55 +Belgien (2018),SEK,Normalbelopp,678 +Belgien (2018),SEK,Breakfast,-101.7 +Belgien (2018),SEK,Lunch,-237.3 +Belgien (2018),SEK,Dinner,-237.3 +Belgien (2019),SEK,Normalbelopp,723 +Belgien (2019),SEK,Breakfast,-108.45 +Belgien (2019),SEK,Lunch,-253.05 +Belgien (2019),SEK,Dinner,-253.05 +Belgien (2020),SEK,Normalbelopp,756 +Belgien (2020),SEK,Breakfast,-113.4 +Belgien (2020),SEK,Lunch,-264.6 +Belgien (2020),SEK,Dinner,-264.6 +Belize (2018),SEK,Normalbelopp,453 +Belize (2018),SEK,Breakfast,-67.95 +Belize (2018),SEK,Lunch,-158.55 +Belize (2018),SEK,Dinner,-158.55 +Belize (2019),SEK,Normalbelopp,485 +Belize (2019),SEK,Breakfast,-72.75 +Belize (2019),SEK,Lunch,-169.75 +Belize (2019),SEK,Dinner,-169.75 +Belize (2020),SEK,Normalbelopp,524 +Belize (2020),SEK,Breakfast,-78.6 +Belize (2020),SEK,Lunch,-183.4 +Belize (2020),SEK,Dinner,-183.4 +Benin (2018),SEK,Normalbelopp,471 +Benin (2018),SEK,Breakfast,-70.65 +Benin (2018),SEK,Lunch,-164.85 +Benin (2018),SEK,Dinner,-164.85 +Benin (2019),SEK,Normalbelopp,507 +Benin (2019),SEK,Breakfast,-76.05 +Benin (2019),SEK,Lunch,-177.45 +Benin (2019),SEK,Dinner,-177.45 +Benin (2020),SEK,Normalbelopp,523 +Benin (2020),SEK,Breakfast,-78.45 +Benin (2020),SEK,Lunch,-183.05 +Benin (2020),SEK,Dinner,-183.05 +Bolivia (2018),SEK,Normalbelopp,280 +Bolivia (2018),SEK,Breakfast,-42 +Bolivia (2018),SEK,Lunch,-98 +Bolivia (2018),SEK,Dinner,-98 +Bolivia (2019),SEK,Normalbelopp,322 +Bolivia (2019),SEK,Breakfast,-48.3 +Bolivia (2019),SEK,Lunch,-112.7 +Bolivia (2019),SEK,Dinner,-112.7 +Bolivia (2020),SEK,Normalbelopp,363 +Bolivia (2020),SEK,Breakfast,-54.45 +Bolivia (2020),SEK,Lunch,-127.05 +Bolivia (2020),SEK,Dinner,-127.05 +Bosnien-Hercegovina (2018),SEK,Normalbelopp,323 +Bosnien-Hercegovina (2018),SEK,Breakfast,-48.45 +Bosnien-Hercegovina (2018),SEK,Lunch,-113.05 +Bosnien-Hercegovina (2018),SEK,Dinner,-113.05 +Bosnien-Hercegovina (2019),SEK,Normalbelopp,352 +Bosnien-Hercegovina (2019),SEK,Breakfast,-52.8 +Bosnien-Hercegovina (2019),SEK,Lunch,-123.2 +Bosnien-Hercegovina (2019),SEK,Dinner,-123.2 +Bosnien-Hercegovina (2020),SEK,Normalbelopp,357 +Bosnien-Hercegovina (2020),SEK,Breakfast,-53.55 +Bosnien-Hercegovina (2020),SEK,Lunch,-124.95 +Bosnien-Hercegovina (2020),SEK,Dinner,-124.95 +Botswana (2018),SEK,Normalbelopp,259 +Botswana (2018),SEK,Breakfast,-38.85 +Botswana (2018),SEK,Lunch,-90.65 +Botswana (2018),SEK,Dinner,-90.65 +Botswana (2019),SEK,Normalbelopp,301 +Botswana (2019),SEK,Breakfast,-45.15 +Botswana (2019),SEK,Lunch,-105.35 +Botswana (2019),SEK,Dinner,-105.35 +Botswana (2020),SEK,Normalbelopp,357 +Botswana (2020),SEK,Breakfast,-53.55 +Botswana (2020),SEK,Lunch,-124.95 +Botswana (2020),SEK,Dinner,-124.95 +Brasilien (2018),SEK,Normalbelopp,419 +Brasilien (2018),SEK,Breakfast,-62.85 +Brasilien (2018),SEK,Lunch,-146.65 +Brasilien (2018),SEK,Dinner,-146.65 +Brasilien (2019),SEK,Normalbelopp,411 +Brasilien (2019),SEK,Breakfast,-61.65 +Brasilien (2019),SEK,Lunch,-143.85 +Brasilien (2019),SEK,Dinner,-143.85 +Brasilien (2020),SEK,Normalbelopp,424 +Brasilien (2020),SEK,Breakfast,-63.6 +Brasilien (2020),SEK,Lunch,-148.4 +Brasilien (2020),SEK,Dinner,-148.4 +Brunei Darussalam (2018),SEK,Normalbelopp,366 +Brunei Darussalam (2018),SEK,Breakfast,-54.9 +Brunei Darussalam (2018),SEK,Lunch,-128.1 +Brunei Darussalam (2018),SEK,Dinner,-128.1 +Brunei Darussalam (2019),SEK,Normalbelopp,426 +Brunei Darussalam (2019),SEK,Breakfast,-63.9 +Brunei Darussalam (2019),SEK,Lunch,-149.1 +Brunei Darussalam (2019),SEK,Dinner,-149.1 +Brunei Darussalam (2020),SEK,Normalbelopp,470 +Brunei Darussalam (2020),SEK,Breakfast,-70.5 +Brunei Darussalam (2020),SEK,Lunch,-164.5 +Brunei Darussalam (2020),SEK,Dinner,-164.5 +Bulgarien (2018),SEK,Normalbelopp,347 +Bulgarien (2018),SEK,Breakfast,-52.05 +Bulgarien (2018),SEK,Lunch,-121.45 +Bulgarien (2018),SEK,Dinner,-121.45 +Bulgarien (2019),SEK,Normalbelopp,365 +Bulgarien (2019),SEK,Breakfast,-54.75 +Bulgarien (2019),SEK,Lunch,-127.75 +Bulgarien (2019),SEK,Dinner,-127.75 +Bulgarien (2020),SEK,Normalbelopp,375 +Bulgarien (2020),SEK,Breakfast,-56.25 +Bulgarien (2020),SEK,Lunch,-131.25 +Bulgarien (2020),SEK,Dinner,-131.25 +Burkina Faso (2018),SEK,Normalbelopp,400 +Burkina Faso (2018),SEK,Breakfast,-60 +Burkina Faso (2018),SEK,Lunch,-140 +Burkina Faso (2018),SEK,Dinner,-140 +Burkina Faso (2019),SEK,Normalbelopp,411 +Burkina Faso (2019),SEK,Breakfast,-61.65 +Burkina Faso (2019),SEK,Lunch,-143.85 +Burkina Faso (2019),SEK,Dinner,-143.85 +Burkina Faso (2020),SEK,Normalbelopp,419 +Burkina Faso (2020),SEK,Breakfast,-62.85 +Burkina Faso (2020),SEK,Lunch,-146.65 +Burkina Faso (2020),SEK,Dinner,-146.65 +Burma (2018),SEK,Normalbelopp,315 +Burma (2018),SEK,Breakfast,-47.25 +Burma (2018),SEK,Lunch,-110.25 +Burma (2018),SEK,Dinner,-110.25 +Burma (2019),SEK,Normalbelopp,286 +Burma (2019),SEK,Breakfast,-42.9 +Burma (2019),SEK,Lunch,-100.1 +Burma (2019),SEK,Dinner,-100.1 +Burma (2020),SEK,Normalbelopp,318 +Burma (2020),SEK,Breakfast,-47.7 +Burma (2020),SEK,Lunch,-111.3 +Burma (2020),SEK,Dinner,-111.3 +Centralafrikanska republiken (2018),SEK,Normalbelopp,393 +Centralafrikanska republiken (2018),SEK,Breakfast,-58.95 +Centralafrikanska republiken (2018),SEK,Lunch,-137.55 +Centralafrikanska republiken (2018),SEK,Dinner,-137.55 +Centralafrikanska republiken (2019),SEK,Normalbelopp,436 +Centralafrikanska republiken (2019),SEK,Breakfast,-65.4 +Centralafrikanska republiken (2019),SEK,Lunch,-152.6 +Centralafrikanska republiken (2019),SEK,Dinner,-152.6 +Centralafrikanska republiken (2020),SEK,Normalbelopp,463 +Centralafrikanska republiken (2020),SEK,Breakfast,-69.45 +Centralafrikanska republiken (2020),SEK,Lunch,-162.05 +Centralafrikanska republiken (2020),SEK,Dinner,-162.05 +Chile (2018),SEK,Normalbelopp,424 +Chile (2018),SEK,Breakfast,-63.6 +Chile (2018),SEK,Lunch,-148.4 +Chile (2018),SEK,Dinner,-148.4 +Chile (2019),SEK,Normalbelopp,422 +Chile (2019),SEK,Breakfast,-63.3 +Chile (2019),SEK,Lunch,-147.7 +Chile (2019),SEK,Dinner,-147.7 +Chile (2020),SEK,Normalbelopp,436 +Chile (2020),SEK,Breakfast,-65.4 +Chile (2020),SEK,Lunch,-152.6 +Chile (2020),SEK,Dinner,-152.6 +Colombia (2018),SEK,Normalbelopp,329 +Colombia (2018),SEK,Breakfast,-49.35 +Colombia (2018),SEK,Lunch,-115.15 +Colombia (2018),SEK,Dinner,-115.15 +Colombia (2019),SEK,Normalbelopp,345 +Colombia (2019),SEK,Breakfast,-51.75 +Colombia (2019),SEK,Lunch,-120.75 +Colombia (2019),SEK,Dinner,-120.75 +Colombia (2020),SEK,Normalbelopp,345 +Colombia (2020),SEK,Breakfast,-51.75 +Colombia (2020),SEK,Lunch,-120.75 +Colombia (2020),SEK,Dinner,-120.75 +Costa Rica (2018),SEK,Normalbelopp,445 +Costa Rica (2018),SEK,Breakfast,-66.75 +Costa Rica (2018),SEK,Lunch,-155.75 +Costa Rica (2018),SEK,Dinner,-155.75 +Costa Rica (2019),SEK,Normalbelopp,464 +Costa Rica (2019),SEK,Breakfast,-69.6 +Costa Rica (2019),SEK,Lunch,-162.4 +Costa Rica (2019),SEK,Dinner,-162.4 +Costa Rica (2020),SEK,Normalbelopp,534 +Costa Rica (2020),SEK,Breakfast,-80.1 +Costa Rica (2020),SEK,Lunch,-186.9 +Costa Rica (2020),SEK,Dinner,-186.9 +Cypern (2018),SEK,Normalbelopp,543 +Cypern (2018),SEK,Breakfast,-81.45 +Cypern (2018),SEK,Lunch,-190.05 +Cypern (2018),SEK,Dinner,-190.05 +Cypern (2019),SEK,Normalbelopp,505 +Cypern (2019),SEK,Breakfast,-75.75 +Cypern (2019),SEK,Lunch,-176.75 +Cypern (2019),SEK,Dinner,-176.75 +Cypern (2020),SEK,Normalbelopp,605 +Cypern (2020),SEK,Breakfast,-90.75 +Cypern (2020),SEK,Lunch,-211.75 +Cypern (2020),SEK,Dinner,-211.75 +Danmark (2018),SEK,Normalbelopp,915 +Danmark (2018),SEK,Breakfast,-137.25 +Danmark (2018),SEK,Lunch,-320.25 +Danmark (2018),SEK,Dinner,-320.25 +Danmark (2019),SEK,Normalbelopp,993 +Danmark (2019),SEK,Breakfast,-148.95 +Danmark (2019),SEK,Lunch,-347.55 +Danmark (2019),SEK,Dinner,-347.55 +Danmark (2020),SEK,Normalbelopp,1016 +Danmark (2020),SEK,Breakfast,-152.4 +Danmark (2020),SEK,Lunch,-355.6 +Danmark (2020),SEK,Dinner,-355.6 +Djibouti (2018),SEK,Normalbelopp,480 +Djibouti (2018),SEK,Breakfast,-72 +Djibouti (2018),SEK,Lunch,-168 +Djibouti (2018),SEK,Dinner,-168 +Djibouti (2019),SEK,Normalbelopp,529 +Djibouti (2019),SEK,Breakfast,-79.35 +Djibouti (2019),SEK,Lunch,-185.15 +Djibouti (2019),SEK,Dinner,-185.15 +Djibouti (2020),SEK,Normalbelopp,561 +Djibouti (2020),SEK,Breakfast,-84.15 +Djibouti (2020),SEK,Lunch,-196.35 +Djibouti (2020),SEK,Dinner,-196.35 +Ecuador (2018),SEK,Normalbelopp,512 +Ecuador (2018),SEK,Breakfast,-76.8 +Ecuador (2018),SEK,Lunch,-179.2 +Ecuador (2018),SEK,Dinner,-179.2 +Ecuador (2019),SEK,Normalbelopp,562 +Ecuador (2019),SEK,Breakfast,-84.3 +Ecuador (2019),SEK,Lunch,-196.7 +Ecuador (2019),SEK,Dinner,-196.7 +Ecuador (2020),SEK,Normalbelopp,592 +Ecuador (2020),SEK,Breakfast,-88.8 +Ecuador (2020),SEK,Lunch,-207.2 +Ecuador (2020),SEK,Dinner,-207.2 +Egypten (2018),SEK,Normalbelopp,230 +Egypten (2018),SEK,Breakfast,-34.5 +Egypten (2018),SEK,Lunch,-80.5 +Egypten (2018),SEK,Dinner,-80.5 +Egypten (2019),SEK,Normalbelopp,233 +Egypten (2019),SEK,Breakfast,-34.95 +Egypten (2019),SEK,Lunch,-81.55 +Egypten (2019),SEK,Dinner,-81.55 +Egypten (2020),SEK,Normalbelopp,302 +Egypten (2020),SEK,Breakfast,-45.3 +Egypten (2020),SEK,Lunch,-105.7 +Egypten (2020),SEK,Dinner,-105.7 +El Salvador (2018),SEK,Normalbelopp,405 +El Salvador (2018),SEK,Breakfast,-60.75 +El Salvador (2018),SEK,Lunch,-141.75 +El Salvador (2018),SEK,Dinner,-141.75 +El Salvador (2019),SEK,Normalbelopp,449 +El Salvador (2019),SEK,Breakfast,-67.35 +El Salvador (2019),SEK,Lunch,-157.15 +El Salvador (2019),SEK,Dinner,-157.15 +El Salvador (2020),SEK,Normalbelopp,484 +El Salvador (2020),SEK,Breakfast,-72.6 +El Salvador (2020),SEK,Lunch,-169.4 +El Salvador (2020),SEK,Dinner,-169.4 +Elfenbenskusten (2018),SEK,Normalbelopp,512 +Elfenbenskusten (2018),SEK,Breakfast,-76.8 +Elfenbenskusten (2018),SEK,Lunch,-179.2 +Elfenbenskusten (2018),SEK,Dinner,-179.2 +Elfenbenskusten (2019),SEK,Normalbelopp,562 +Elfenbenskusten (2019),SEK,Breakfast,-84.3 +Elfenbenskusten (2019),SEK,Lunch,-196.7 +Elfenbenskusten (2019),SEK,Dinner,-196.7 +Elfenbenskusten (2020),SEK,Normalbelopp,608 +Elfenbenskusten (2020),SEK,Breakfast,-91.2 +Elfenbenskusten (2020),SEK,Lunch,-212.8 +Elfenbenskusten (2020),SEK,Dinner,-212.8 +Eritrea (2018),SEK,Normalbelopp,471 +Eritrea (2018),SEK,Breakfast,-70.65 +Eritrea (2018),SEK,Lunch,-164.85 +Eritrea (2018),SEK,Dinner,-164.85 +Eritrea (2019),SEK,Normalbelopp,515 +Eritrea (2019),SEK,Breakfast,-77.25 +Eritrea (2019),SEK,Lunch,-180.25 +Eritrea (2019),SEK,Dinner,-180.25 +Eritrea (2020),SEK,Normalbelopp,468 +Eritrea (2020),SEK,Breakfast,-70.2 +Eritrea (2020),SEK,Lunch,-163.8 +Eritrea (2020),SEK,Dinner,-163.8 +Estland (2018),SEK,Normalbelopp,459 +Estland (2018),SEK,Breakfast,-68.85 +Estland (2018),SEK,Lunch,-160.65 +Estland (2018),SEK,Dinner,-160.65 +Estland (2019),SEK,Normalbelopp,491 +Estland (2019),SEK,Breakfast,-73.65 +Estland (2019),SEK,Lunch,-171.85 +Estland (2019),SEK,Dinner,-171.85 +Estland (2020),SEK,Normalbelopp,506 +Estland (2020),SEK,Breakfast,-75.9 +Estland (2020),SEK,Lunch,-177.1 +Estland (2020),SEK,Dinner,-177.1 +Etiopien (2018),SEK,Normalbelopp,230 +Etiopien (2018),SEK,Breakfast,-34.5 +Etiopien (2018),SEK,Lunch,-80.5 +Etiopien (2018),SEK,Dinner,-80.5 +Etiopien (2019),SEK,Normalbelopp,265 +Etiopien (2019),SEK,Breakfast,-39.75 +Etiopien (2019),SEK,Lunch,-92.75 +Etiopien (2019),SEK,Dinner,-92.75 +Etiopien (2020),SEK,Normalbelopp,266 +Etiopien (2020),SEK,Breakfast,-39.9 +Etiopien (2020),SEK,Lunch,-93.1 +Etiopien (2020),SEK,Dinner,-93.1 +Filippinerna (2018),SEK,Normalbelopp,357 +Filippinerna (2018),SEK,Breakfast,-53.55 +Filippinerna (2018),SEK,Lunch,-124.95 +Filippinerna (2018),SEK,Dinner,-124.95 +Filippinerna (2019),SEK,Normalbelopp,384 +Filippinerna (2019),SEK,Breakfast,-57.6 +Filippinerna (2019),SEK,Lunch,-134.4 +Filippinerna (2019),SEK,Dinner,-134.4 +Filippinerna (2020),SEK,Normalbelopp,441 +Filippinerna (2020),SEK,Breakfast,-66.15 +Filippinerna (2020),SEK,Lunch,-154.35 +Filippinerna (2020),SEK,Dinner,-154.35 +Finland (2018),SEK,Normalbelopp,680 +Finland (2018),SEK,Breakfast,-102 +Finland (2018),SEK,Lunch,-238 +Finland (2018),SEK,Dinner,-238 +Finland (2019),SEK,Normalbelopp,729 +Finland (2019),SEK,Breakfast,-109.35 +Finland (2019),SEK,Lunch,-255.15 +Finland (2019),SEK,Dinner,-255.15 +Finland (2020),SEK,Normalbelopp,759 +Finland (2020),SEK,Breakfast,-113.85 +Finland (2020),SEK,Lunch,-265.65 +Finland (2020),SEK,Dinner,-265.65 +Förenade Arabemiraten (2018),SEK,Normalbelopp,703 +Förenade Arabemiraten (2018),SEK,Breakfast,-105.45 +Förenade Arabemiraten (2018),SEK,Lunch,-246.05 +Förenade Arabemiraten (2018),SEK,Dinner,-246.05 +Förenade Arabemiraten (2019),SEK,Normalbelopp,849 +Förenade Arabemiraten (2019),SEK,Breakfast,-127.35 +Förenade Arabemiraten (2019),SEK,Lunch,-297.15 +Förenade Arabemiraten (2019),SEK,Dinner,-297.15 +Förenade Arabemiraten (2020),SEK,Normalbelopp,899 +Förenade Arabemiraten (2020),SEK,Breakfast,-134.85 +Förenade Arabemiraten (2020),SEK,Lunch,-314.65 +Förenade Arabemiraten (2020),SEK,Dinner,-314.65 +Frankrike (2018),SEK,Normalbelopp,714 +Frankrike (2018),SEK,Breakfast,-107.1 +Frankrike (2018),SEK,Lunch,-249.9 +Frankrike (2018),SEK,Dinner,-249.9 +Frankrike (2019),SEK,Normalbelopp,760 +Frankrike (2019),SEK,Breakfast,-114 +Frankrike (2019),SEK,Lunch,-266 +Frankrike (2019),SEK,Dinner,-266 +Frankrike (2020),SEK,Normalbelopp,794 +Frankrike (2020),SEK,Breakfast,-119.1 +Frankrike (2020),SEK,Lunch,-277.9 +Frankrike (2020),SEK,Dinner,-277.9 +Gabon (2018),SEK,Normalbelopp,708 +Gabon (2018),SEK,Breakfast,-106.2 +Gabon (2018),SEK,Lunch,-247.8 +Gabon (2018),SEK,Dinner,-247.8 +Gabon (2019),SEK,Normalbelopp,742 +Gabon (2019),SEK,Breakfast,-111.3 +Gabon (2019),SEK,Lunch,-259.7 +Gabon (2019),SEK,Dinner,-259.7 +Gabon (2020),SEK,Normalbelopp,751 +Gabon (2020),SEK,Breakfast,-112.65 +Gabon (2020),SEK,Lunch,-262.85 +Gabon (2020),SEK,Dinner,-262.85 +Gambia (2018),SEK,Normalbelopp,237 +Gambia (2018),SEK,Breakfast,-35.55 +Gambia (2018),SEK,Lunch,-82.95 +Gambia (2018),SEK,Dinner,-82.95 +Gambia (2019),SEK,Normalbelopp,244 +Gambia (2019),SEK,Breakfast,-36.6 +Gambia (2019),SEK,Lunch,-85.4 +Gambia (2019),SEK,Dinner,-85.4 +Gambia (2020),SEK,Normalbelopp,260 +Gambia (2020),SEK,Breakfast,-39 +Gambia (2020),SEK,Lunch,-91 +Gambia (2020),SEK,Dinner,-91 +Georgien (2018),SEK,Normalbelopp,230 +Georgien (2018),SEK,Breakfast,-34.5 +Georgien (2018),SEK,Lunch,-80.5 +Georgien (2018),SEK,Dinner,-80.5 +Georgien (2019),SEK,Normalbelopp,235 +Georgien (2019),SEK,Breakfast,-35.25 +Georgien (2019),SEK,Lunch,-82.25 +Georgien (2019),SEK,Dinner,-82.25 +Georgien (2020),SEK,Normalbelopp,240 +Georgien (2020),SEK,Breakfast,-36 +Georgien (2020),SEK,Lunch,-84 +Georgien (2020),SEK,Dinner,-84 +Ghana (2018),SEK,Normalbelopp,404 +Ghana (2018),SEK,Breakfast,-60.6 +Ghana (2018),SEK,Lunch,-141.4 +Ghana (2018),SEK,Dinner,-141.4 +Ghana (2019),SEK,Normalbelopp,407 +Ghana (2019),SEK,Breakfast,-61.05 +Ghana (2019),SEK,Lunch,-142.45 +Ghana (2019),SEK,Dinner,-142.45 +Ghana (2020),SEK,Normalbelopp,372 +Ghana (2020),SEK,Breakfast,-55.8 +Ghana (2020),SEK,Lunch,-130.2 +Ghana (2020),SEK,Dinner,-130.2 +Grekland (2018),SEK,Normalbelopp,589 +Grekland (2018),SEK,Breakfast,-88.35 +Grekland (2018),SEK,Lunch,-206.15 +Grekland (2018),SEK,Dinner,-206.15 +Grekland (2019),SEK,Normalbelopp,625 +Grekland (2019),SEK,Breakfast,-93.75 +Grekland (2019),SEK,Lunch,-218.75 +Grekland (2019),SEK,Dinner,-218.75 +Grekland (2020),SEK,Normalbelopp,650 +Grekland (2020),SEK,Breakfast,-97.5 +Grekland (2020),SEK,Lunch,-227.5 +Grekland (2020),SEK,Dinner,-227.5 +Grenada (2018),SEK,Normalbelopp,477 +Grenada (2018),SEK,Breakfast,-71.55 +Grenada (2018),SEK,Lunch,-166.95 +Grenada (2018),SEK,Dinner,-166.95 +Grenada (2019),SEK,Normalbelopp,550 +Grenada (2019),SEK,Breakfast,-82.5 +Grenada (2019),SEK,Lunch,-192.5 +Grenada (2019),SEK,Dinner,-192.5 +Grenada (2020),SEK,Normalbelopp,581 +Grenada (2020),SEK,Breakfast,-87.15 +Grenada (2020),SEK,Lunch,-203.35 +Grenada (2020),SEK,Dinner,-203.35 +Grönland (2018),SEK,Normalbelopp,915 +Grönland (2018),SEK,Breakfast,-137.25 +Grönland (2018),SEK,Lunch,-320.25 +Grönland (2018),SEK,Dinner,-320.25 +Grönland (2019),SEK,Normalbelopp,993 +Grönland (2019),SEK,Breakfast,-148.95 +Grönland (2019),SEK,Lunch,-347.55 +Grönland (2019),SEK,Dinner,-347.55 +Grönland (2020),SEK,Normalbelopp,1016 +Grönland (2020),SEK,Breakfast,-152.4 +Grönland (2020),SEK,Lunch,-355.6 +Grönland (2020),SEK,Dinner,-355.6 +Guinea (2018),SEK,Normalbelopp,400 +Guinea (2018),SEK,Breakfast,-60 +Guinea (2018),SEK,Lunch,-140 +Guinea (2018),SEK,Dinner,-140 +Guinea (2019),SEK,Normalbelopp,444 +Guinea (2019),SEK,Breakfast,-66.6 +Guinea (2019),SEK,Lunch,-155.4 +Guinea (2019),SEK,Dinner,-155.4 +Guinea (2020),SEK,Normalbelopp,475 +Guinea (2020),SEK,Breakfast,-71.25 +Guinea (2020),SEK,Lunch,-166.25 +Guinea (2020),SEK,Dinner,-166.25 +Guyana (2018),SEK,Normalbelopp,494 +Guyana (2018),SEK,Breakfast,-74.1 +Guyana (2018),SEK,Lunch,-172.9 +Guyana (2018),SEK,Dinner,-172.9 +Guyana (2019),SEK,Normalbelopp,518 +Guyana (2019),SEK,Breakfast,-77.7 +Guyana (2019),SEK,Lunch,-181.3 +Guyana (2019),SEK,Dinner,-181.3 +Guyana (2020),SEK,Normalbelopp,548 +Guyana (2020),SEK,Breakfast,-82.2 +Guyana (2020),SEK,Lunch,-191.8 +Guyana (2020),SEK,Dinner,-191.8 +Haiti (2018),SEK,Normalbelopp,525 +Haiti (2018),SEK,Breakfast,-78.75 +Haiti (2018),SEK,Lunch,-183.75 +Haiti (2018),SEK,Dinner,-183.75 +Haiti (2019),SEK,Normalbelopp,548 +Haiti (2019),SEK,Breakfast,-82.2 +Haiti (2019),SEK,Lunch,-191.8 +Haiti (2019),SEK,Dinner,-191.8 +Haiti (2020),SEK,Normalbelopp,451 +Haiti (2020),SEK,Breakfast,-67.65 +Haiti (2020),SEK,Lunch,-157.85 +Haiti (2020),SEK,Dinner,-157.85 +Honduras (2018),SEK,Normalbelopp,312 +Honduras (2018),SEK,Breakfast,-46.8 +Honduras (2018),SEK,Lunch,-109.2 +Honduras (2018),SEK,Dinner,-109.2 +Honduras (2019),SEK,Normalbelopp,328 +Honduras (2019),SEK,Breakfast,-49.2 +Honduras (2019),SEK,Lunch,-114.8 +Honduras (2019),SEK,Dinner,-114.8 +Honduras (2020),SEK,Normalbelopp,351 +Honduras (2020),SEK,Breakfast,-52.65 +Honduras (2020),SEK,Lunch,-122.85 +Honduras (2020),SEK,Dinner,-122.85 +Hong Kong (2018),SEK,Normalbelopp,538 +Hong Kong (2018),SEK,Breakfast,-80.7 +Hong Kong (2018),SEK,Lunch,-188.3 +Hong Kong (2018),SEK,Dinner,-188.3 +Hong Kong (2019),SEK,Normalbelopp,578 +Hong Kong (2019),SEK,Breakfast,-86.7 +Hong Kong (2019),SEK,Lunch,-202.3 +Hong Kong (2019),SEK,Dinner,-202.3 +Hong Kong (2020),SEK,Normalbelopp,590 +Hong Kong (2020),SEK,Breakfast,-88.5 +Hong Kong (2020),SEK,Lunch,-206.5 +Hong Kong (2020),SEK,Dinner,-206.5 +Indien (2018),SEK,Normalbelopp,319 +Indien (2018),SEK,Breakfast,-47.85 +Indien (2018),SEK,Lunch,-111.65 +Indien (2018),SEK,Dinner,-111.65 +Indien (2019),SEK,Normalbelopp,320 +Indien (2019),SEK,Breakfast,-48 +Indien (2019),SEK,Lunch,-112 +Indien (2019),SEK,Dinner,-112 +Indien (2020),SEK,Normalbelopp,356 +Indien (2020),SEK,Breakfast,-53.4 +Indien (2020),SEK,Lunch,-124.6 +Indien (2020),SEK,Dinner,-124.6 +Indonesien (2018),SEK,Normalbelopp,358 +Indonesien (2018),SEK,Breakfast,-53.7 +Indonesien (2018),SEK,Lunch,-125.3 +Indonesien (2018),SEK,Dinner,-125.3 +Indonesien (2019),SEK,Normalbelopp,348 +Indonesien (2019),SEK,Breakfast,-52.2 +Indonesien (2019),SEK,Lunch,-121.8 +Indonesien (2019),SEK,Dinner,-121.8 +Indonesien (2020),SEK,Normalbelopp,404 +Indonesien (2020),SEK,Breakfast,-60.6 +Indonesien (2020),SEK,Lunch,-141.4 +Indonesien (2020),SEK,Dinner,-141.4 +Irak (2018),SEK,Normalbelopp,626 +Irak (2018),SEK,Breakfast,-93.9 +Irak (2018),SEK,Lunch,-219.1 +Irak (2018),SEK,Dinner,-219.1 +Irak (2019),SEK,Normalbelopp,671 +Irak (2019),SEK,Breakfast,-100.65 +Irak (2019),SEK,Lunch,-234.85 +Irak (2019),SEK,Dinner,-234.85 +Irak (2020),SEK,Normalbelopp,703 +Irak (2020),SEK,Breakfast,-105.45 +Irak (2020),SEK,Lunch,-246.05 +Irak (2020),SEK,Dinner,-246.05 +Iran (2018),SEK,Normalbelopp,410 +Iran (2018),SEK,Breakfast,-61.5 +Iran (2018),SEK,Lunch,-143.5 +Iran (2018),SEK,Dinner,-143.5 +Iran (2019),SEK,Normalbelopp,362 +Iran (2019),SEK,Breakfast,-54.3 +Iran (2019),SEK,Lunch,-126.7 +Iran (2019),SEK,Dinner,-126.7 +Iran (2020),SEK,Normalbelopp,452 +Iran (2020),SEK,Breakfast,-67.8 +Iran (2020),SEK,Lunch,-158.2 +Iran (2020),SEK,Dinner,-158.2 +Irland (2018),SEK,Normalbelopp,654 +Irland (2018),SEK,Breakfast,-98.1 +Irland (2018),SEK,Lunch,-228.9 +Irland (2018),SEK,Dinner,-228.9 +Irland (2019),SEK,Normalbelopp,703 +Irland (2019),SEK,Breakfast,-105.45 +Irland (2019),SEK,Lunch,-246.05 +Irland (2019),SEK,Dinner,-246.05 +Irland (2020),SEK,Normalbelopp,727 +Irland (2020),SEK,Breakfast,-109.05 +Irland (2020),SEK,Lunch,-254.45 +Irland (2020),SEK,Dinner,-254.45 +Island (2018),SEK,Normalbelopp,837 +Island (2018),SEK,Breakfast,-125.55 +Island (2018),SEK,Lunch,-292.95 +Island (2018),SEK,Dinner,-292.95 +Island (2019),SEK,Normalbelopp,798 +Island (2019),SEK,Breakfast,-119.7 +Island (2019),SEK,Lunch,-279.3 +Island (2019),SEK,Dinner,-279.3 +Island (2020),SEK,Normalbelopp,838 +Island (2020),SEK,Breakfast,-125.7 +Island (2020),SEK,Lunch,-293.3 +Island (2020),SEK,Dinner,-293.3 +Israel (2018),SEK,Normalbelopp,828 +Israel (2018),SEK,Breakfast,-124.2 +Israel (2018),SEK,Lunch,-289.8 +Israel (2018),SEK,Dinner,-289.8 +Israel (2019),SEK,Normalbelopp,822 +Israel (2019),SEK,Breakfast,-123.3 +Israel (2019),SEK,Lunch,-287.7 +Israel (2019),SEK,Dinner,-287.7 +Israel (2020),SEK,Normalbelopp,921 +Israel (2020),SEK,Breakfast,-138.15 +Israel (2020),SEK,Lunch,-322.35 +Israel (2020),SEK,Dinner,-322.35 +Italien (2018),SEK,Normalbelopp,540 +Italien (2018),SEK,Breakfast,-81 +Italien (2018),SEK,Lunch,-189 +Italien (2018),SEK,Dinner,-189 +Italien (2019),SEK,Normalbelopp,590 +Italien (2019),SEK,Breakfast,-88.5 +Italien (2019),SEK,Lunch,-206.5 +Italien (2019),SEK,Dinner,-206.5 +Italien (2020),SEK,Normalbelopp,627 +Italien (2020),SEK,Breakfast,-94.05 +Italien (2020),SEK,Lunch,-219.45 +Italien (2020),SEK,Dinner,-219.45 +Jamaica (2018),SEK,Normalbelopp,475 +Jamaica (2018),SEK,Breakfast,-71.25 +Jamaica (2018),SEK,Lunch,-166.25 +Jamaica (2018),SEK,Dinner,-166.25 +Jamaica (2019),SEK,Normalbelopp,539 +Jamaica (2019),SEK,Breakfast,-80.85 +Jamaica (2019),SEK,Lunch,-188.65 +Jamaica (2019),SEK,Dinner,-188.65 +Jamaica (2020),SEK,Normalbelopp,519 +Jamaica (2020),SEK,Breakfast,-77.85 +Jamaica (2020),SEK,Lunch,-181.65 +Jamaica (2020),SEK,Dinner,-181.65 +Japan (2018),SEK,Normalbelopp,503 +Japan (2018),SEK,Breakfast,-75.45 +Japan (2018),SEK,Lunch,-176.05 +Japan (2018),SEK,Dinner,-176.05 +Japan (2019),SEK,Normalbelopp,537 +Japan (2019),SEK,Breakfast,-80.55 +Japan (2019),SEK,Lunch,-187.95 +Japan (2019),SEK,Dinner,-187.95 +Japan (2020),SEK,Normalbelopp,587 +Japan (2020),SEK,Breakfast,-88.05 +Japan (2020),SEK,Lunch,-205.45 +Japan (2020),SEK,Dinner,-205.45 +Jordanien (2018),SEK,Normalbelopp,651 +Jordanien (2018),SEK,Breakfast,-97.65 +Jordanien (2018),SEK,Lunch,-227.85 +Jordanien (2018),SEK,Dinner,-227.85 +Jordanien (2019),SEK,Normalbelopp,709 +Jordanien (2019),SEK,Breakfast,-106.35 +Jordanien (2019),SEK,Lunch,-248.15 +Jordanien (2019),SEK,Dinner,-248.15 +Jordanien (2020),SEK,Normalbelopp,748 +Jordanien (2020),SEK,Breakfast,-112.2 +Jordanien (2020),SEK,Lunch,-261.8 +Jordanien (2020),SEK,Dinner,-261.8 +Kambodja (2018),SEK,Normalbelopp,380 +Kambodja (2018),SEK,Breakfast,-57 +Kambodja (2018),SEK,Lunch,-133 +Kambodja (2018),SEK,Dinner,-133 +Kambodja (2019),SEK,Normalbelopp,434 +Kambodja (2019),SEK,Breakfast,-65.1 +Kambodja (2019),SEK,Lunch,-151.9 +Kambodja (2019),SEK,Dinner,-151.9 +Kambodja (2020),SEK,Normalbelopp,485 +Kambodja (2020),SEK,Breakfast,-72.75 +Kambodja (2020),SEK,Lunch,-169.75 +Kambodja (2020),SEK,Dinner,-169.75 +Kamerun (2018),SEK,Normalbelopp,491 +Kamerun (2018),SEK,Breakfast,-73.65 +Kamerun (2018),SEK,Lunch,-171.85 +Kamerun (2018),SEK,Dinner,-171.85 +Kamerun (2019),SEK,Normalbelopp,504 +Kamerun (2019),SEK,Breakfast,-75.6 +Kamerun (2019),SEK,Lunch,-176.4 +Kamerun (2019),SEK,Dinner,-176.4 +Kamerun (2020),SEK,Normalbelopp,520 +Kamerun (2020),SEK,Breakfast,-78 +Kamerun (2020),SEK,Lunch,-182 +Kamerun (2020),SEK,Dinner,-182 +Kanada (2018),SEK,Normalbelopp,556 +Kanada (2018),SEK,Breakfast,-83.4 +Kanada (2018),SEK,Lunch,-194.6 +Kanada (2018),SEK,Dinner,-194.6 +Kanada (2019),SEK,Normalbelopp,616 +Kanada (2019),SEK,Breakfast,-92.4 +Kanada (2019),SEK,Lunch,-215.6 +Kanada (2019),SEK,Dinner,-215.6 +Kanada (2020),SEK,Normalbelopp,662 +Kanada (2020),SEK,Breakfast,-99.3 +Kanada (2020),SEK,Lunch,-231.7 +Kanada (2020),SEK,Dinner,-231.7 +Kazakstan (2018),SEK,Normalbelopp,262 +Kazakstan (2018),SEK,Breakfast,-39.3 +Kazakstan (2018),SEK,Lunch,-91.7 +Kazakstan (2018),SEK,Dinner,-91.7 +Kazakstan (2019),SEK,Normalbelopp,261 +Kazakstan (2019),SEK,Breakfast,-39.15 +Kazakstan (2019),SEK,Lunch,-91.35 +Kazakstan (2019),SEK,Dinner,-91.35 +Kazakstan (2020),SEK,Normalbelopp,257 +Kazakstan (2020),SEK,Breakfast,-38.55 +Kazakstan (2020),SEK,Lunch,-89.95 +Kazakstan (2020),SEK,Dinner,-89.95 +Kenya (2018),SEK,Normalbelopp,438 +Kenya (2018),SEK,Breakfast,-65.7 +Kenya (2018),SEK,Lunch,-153.3 +Kenya (2018),SEK,Dinner,-153.3 +Kenya (2019),SEK,Normalbelopp,488 +Kenya (2019),SEK,Breakfast,-73.2 +Kenya (2019),SEK,Lunch,-170.8 +Kenya (2019),SEK,Dinner,-170.8 +Kenya (2020),SEK,Normalbelopp,505 +Kenya (2020),SEK,Breakfast,-75.75 +Kenya (2020),SEK,Lunch,-176.75 +Kenya (2020),SEK,Dinner,-176.75 +Kina (2018),SEK,Normalbelopp,538 +Kina (2018),SEK,Breakfast,-80.7 +Kina (2018),SEK,Lunch,-188.3 +Kina (2018),SEK,Dinner,-188.3 +Kina (2019),SEK,Normalbelopp,578 +Kina (2019),SEK,Breakfast,-86.7 +Kina (2019),SEK,Lunch,-202.3 +Kina (2019),SEK,Dinner,-202.3 +Kina (2020),SEK,Normalbelopp,590 +Kina (2020),SEK,Breakfast,-88.5 +Kina (2020),SEK,Lunch,-206.5 +Kina (2020),SEK,Dinner,-206.5 +Kirgizistan (2018),SEK,Normalbelopp,230 +Kirgizistan (2018),SEK,Breakfast,-34.5 +Kirgizistan (2018),SEK,Lunch,-80.5 +Kirgizistan (2018),SEK,Dinner,-80.5 +Kirgizistan (2019),SEK,Normalbelopp,259 +Kirgizistan (2019),SEK,Breakfast,-38.85 +Kirgizistan (2019),SEK,Lunch,-90.65 +Kirgizistan (2019),SEK,Dinner,-90.65 +Kirgizistan (2020),SEK,Normalbelopp,271 +Kirgizistan (2020),SEK,Breakfast,-40.65 +Kirgizistan (2020),SEK,Lunch,-94.85 +Kirgizistan (2020),SEK,Dinner,-94.85 +Kongo (Brazzaville) (2018),SEK,Normalbelopp,500 +Kongo (Brazzaville) (2018),SEK,Breakfast,-75 +Kongo (Brazzaville) (2018),SEK,Lunch,-175 +Kongo (Brazzaville) (2018),SEK,Dinner,-175 +Kongo (Brazzaville) (2019),SEK,Normalbelopp,542 +Kongo (Brazzaville) (2019),SEK,Breakfast,-81.3 +Kongo (Brazzaville) (2019),SEK,Lunch,-189.7 +Kongo (Brazzaville) (2019),SEK,Dinner,-189.7 +Kongo (Brazzaville) (2020),SEK,Normalbelopp,560 +Kongo (Brazzaville) (2020),SEK,Breakfast,-84 +Kongo (Brazzaville) (2020),SEK,Lunch,-196 +Kongo (Brazzaville) (2020),SEK,Dinner,-196 +Kongo (Demokratiska Republiken) (2018),SEK,Normalbelopp,464 +Kongo (Demokratiska Republiken) (2018),SEK,Breakfast,-69.6 +Kongo (Demokratiska Republiken) (2018),SEK,Lunch,-162.4 +Kongo (Demokratiska Republiken) (2018),SEK,Dinner,-162.4 +Kongo (Demokratiska Republiken) (2019),SEK,Normalbelopp,638 +Kongo (Demokratiska Republiken) (2019),SEK,Breakfast,-95.7 +Kongo (Demokratiska Republiken) (2019),SEK,Lunch,-223.3 +Kongo (Demokratiska Republiken) (2019),SEK,Dinner,-223.3 +Kongo (Demokratiska Republiken) (2020),SEK,Normalbelopp,634 +Kongo (Demokratiska Republiken) (2020),SEK,Breakfast,-95.1 +Kongo (Demokratiska Republiken) (2020),SEK,Lunch,-221.9 +Kongo (Demokratiska Republiken) (2020),SEK,Dinner,-221.9 +Kosovo (2018),SEK,Normalbelopp,240 +Kosovo (2018),SEK,Breakfast,-36 +Kosovo (2018),SEK,Lunch,-84 +Kosovo (2018),SEK,Dinner,-84 +Kosovo (2019),SEK,Normalbelopp,246 +Kosovo (2019),SEK,Breakfast,-36.9 +Kosovo (2019),SEK,Lunch,-86.1 +Kosovo (2019),SEK,Dinner,-86.1 +Kosovo (2020),SEK,Normalbelopp,240 +Kosovo (2020),SEK,Breakfast,-36 +Kosovo (2020),SEK,Lunch,-84 +Kosovo (2020),SEK,Dinner,-84 +Kroatien (2018),SEK,Normalbelopp,410 +Kroatien (2018),SEK,Breakfast,-61.5 +Kroatien (2018),SEK,Lunch,-143.5 +Kroatien (2018),SEK,Dinner,-143.5 +Kroatien (2019),SEK,Normalbelopp,439 +Kroatien (2019),SEK,Breakfast,-65.85 +Kroatien (2019),SEK,Lunch,-153.65 +Kroatien (2019),SEK,Dinner,-153.65 +Kroatien (2020),SEK,Normalbelopp,448 +Kroatien (2020),SEK,Breakfast,-67.2 +Kroatien (2020),SEK,Lunch,-156.8 +Kroatien (2020),SEK,Dinner,-156.8 +Kuba (2018),SEK,Normalbelopp,379 +Kuba (2018),SEK,Breakfast,-56.85 +Kuba (2018),SEK,Lunch,-132.65 +Kuba (2018),SEK,Dinner,-132.65 +Kuba (2019),SEK,Normalbelopp,413 +Kuba (2019),SEK,Breakfast,-61.95 +Kuba (2019),SEK,Lunch,-144.55 +Kuba (2019),SEK,Dinner,-144.55 +Kuba (2020),SEK,Normalbelopp,449 +Kuba (2020),SEK,Breakfast,-67.35 +Kuba (2020),SEK,Lunch,-157.15 +Kuba (2020),SEK,Dinner,-157.15 +Kuwait (2018),SEK,Normalbelopp,677 +Kuwait (2018),SEK,Breakfast,-101.55 +Kuwait (2018),SEK,Lunch,-236.95 +Kuwait (2018),SEK,Dinner,-236.95 +Kuwait (2019),SEK,Normalbelopp,741 +Kuwait (2019),SEK,Breakfast,-111.15 +Kuwait (2019),SEK,Lunch,-259.35 +Kuwait (2019),SEK,Dinner,-259.35 +Kuwait (2020),SEK,Normalbelopp,791 +Kuwait (2020),SEK,Breakfast,-118.65 +Kuwait (2020),SEK,Lunch,-276.85 +Kuwait (2020),SEK,Dinner,-276.85 +Laos (2018),SEK,Normalbelopp,278 +Laos (2018),SEK,Breakfast,-41.7 +Laos (2018),SEK,Lunch,-97.3 +Laos (2018),SEK,Dinner,-97.3 +Laos (2019),SEK,Normalbelopp,302 +Laos (2019),SEK,Breakfast,-45.3 +Laos (2019),SEK,Lunch,-105.7 +Laos (2019),SEK,Dinner,-105.7 +Laos (2020),SEK,Normalbelopp,308 +Laos (2020),SEK,Breakfast,-46.2 +Laos (2020),SEK,Lunch,-107.8 +Laos (2020),SEK,Dinner,-107.8 +Lettland (2018),SEK,Normalbelopp,460 +Lettland (2018),SEK,Breakfast,-69 +Lettland (2018),SEK,Lunch,-161 +Lettland (2018),SEK,Dinner,-161 +Lettland (2019),SEK,Normalbelopp,505 +Lettland (2019),SEK,Breakfast,-75.75 +Lettland (2019),SEK,Lunch,-176.75 +Lettland (2019),SEK,Dinner,-176.75 +Lettland (2020),SEK,Normalbelopp,529 +Lettland (2020),SEK,Breakfast,-79.35 +Lettland (2020),SEK,Lunch,-185.15 +Lettland (2020),SEK,Dinner,-185.15 +Libanon (2018),SEK,Normalbelopp,674 +Libanon (2018),SEK,Breakfast,-101.1 +Libanon (2018),SEK,Lunch,-235.9 +Libanon (2018),SEK,Dinner,-235.9 +Libanon (2019),SEK,Normalbelopp,738 +Libanon (2019),SEK,Breakfast,-110.7 +Libanon (2019),SEK,Lunch,-258.3 +Libanon (2019),SEK,Dinner,-258.3 +Libanon (2020),SEK,Normalbelopp,766 +Libanon (2020),SEK,Breakfast,-114.9 +Libanon (2020),SEK,Lunch,-268.1 +Libanon (2020),SEK,Dinner,-268.1 +Liberia (2018),SEK,Normalbelopp,549 +Liberia (2018),SEK,Breakfast,-82.35 +Liberia (2018),SEK,Lunch,-192.15 +Liberia (2018),SEK,Dinner,-192.15 +Liberia (2019),SEK,Normalbelopp,569 +Liberia (2019),SEK,Breakfast,-85.35 +Liberia (2019),SEK,Lunch,-199.15 +Liberia (2019),SEK,Dinner,-199.15 +Liberia (2020),SEK,Normalbelopp,604 +Liberia (2020),SEK,Breakfast,-90.6 +Liberia (2020),SEK,Lunch,-211.4 +Liberia (2020),SEK,Dinner,-211.4 +Libyen (2018),SEK,Normalbelopp,584 +Libyen (2018),SEK,Breakfast,-87.6 +Libyen (2018),SEK,Lunch,-204.4 +Libyen (2018),SEK,Dinner,-204.4 +Libyen (2019),SEK,Normalbelopp,707 +Libyen (2019),SEK,Breakfast,-106.05 +Libyen (2019),SEK,Lunch,-247.45 +Libyen (2019),SEK,Dinner,-247.45 +Libyen (2020),SEK,Normalbelopp,775 +Libyen (2020),SEK,Breakfast,-116.25 +Libyen (2020),SEK,Lunch,-271.25 +Libyen (2020),SEK,Dinner,-271.25 +Liechtenstein (2018),SEK,Normalbelopp,705 +Liechtenstein (2018),SEK,Breakfast,-105.75 +Liechtenstein (2018),SEK,Lunch,-246.75 +Liechtenstein (2018),SEK,Dinner,-246.75 +Liechtenstein (2019),SEK,Normalbelopp,794 +Liechtenstein (2019),SEK,Breakfast,-119.1 +Liechtenstein (2019),SEK,Lunch,-277.9 +Liechtenstein (2019),SEK,Dinner,-277.9 +Liechtenstein (2020),SEK,Normalbelopp,914 +Liechtenstein (2020),SEK,Breakfast,-137.1 +Liechtenstein (2020),SEK,Lunch,-319.9 +Liechtenstein (2020),SEK,Dinner,-319.9 +Litauen (2018),SEK,Normalbelopp,345 +Litauen (2018),SEK,Breakfast,-51.75 +Litauen (2018),SEK,Lunch,-120.75 +Litauen (2018),SEK,Dinner,-120.75 +Litauen (2019),SEK,Normalbelopp,377 +Litauen (2019),SEK,Breakfast,-56.55 +Litauen (2019),SEK,Lunch,-131.95 +Litauen (2019),SEK,Dinner,-131.95 +Litauen (2020),SEK,Normalbelopp,398 +Litauen (2020),SEK,Breakfast,-59.7 +Litauen (2020),SEK,Lunch,-139.3 +Litauen (2020),SEK,Dinner,-139.3 +Luxemburg (2018),SEK,Normalbelopp,669 +Luxemburg (2018),SEK,Breakfast,-100.35 +Luxemburg (2018),SEK,Lunch,-234.15 +Luxemburg (2018),SEK,Dinner,-234.15 +Luxemburg (2019),SEK,Normalbelopp,735 +Luxemburg (2019),SEK,Breakfast,-110.25 +Luxemburg (2019),SEK,Lunch,-257.25 +Luxemburg (2019),SEK,Dinner,-257.25 +Luxemburg (2020),SEK,Normalbelopp,776 +Luxemburg (2020),SEK,Breakfast,-116.4 +Luxemburg (2020),SEK,Lunch,-271.6 +Luxemburg (2020),SEK,Dinner,-271.6 +Macao (2018),SEK,Normalbelopp,538 +Macao (2018),SEK,Breakfast,-80.7 +Macao (2018),SEK,Lunch,-188.3 +Macao (2018),SEK,Dinner,-188.3 +Macao (2019),SEK,Normalbelopp,578 +Macao (2019),SEK,Breakfast,-86.7 +Macao (2019),SEK,Lunch,-202.3 +Macao (2019),SEK,Dinner,-202.3 +Macao (2020),SEK,Normalbelopp,590 +Macao (2020),SEK,Breakfast,-88.5 +Macao (2020),SEK,Lunch,-206.5 +Macao (2020),SEK,Dinner,-206.5 +Madagaskar (2018),SEK,Normalbelopp,230 +Madagaskar (2018),SEK,Breakfast,-34.5 +Madagaskar (2018),SEK,Lunch,-80.5 +Madagaskar (2018),SEK,Dinner,-80.5 +Madagaskar (2019),SEK,Normalbelopp,230 +Madagaskar (2019),SEK,Breakfast,-34.5 +Madagaskar (2019),SEK,Lunch,-80.5 +Madagaskar (2019),SEK,Dinner,-80.5 +Madagaskar (2020),SEK,Normalbelopp,240 +Madagaskar (2020),SEK,Breakfast,-36 +Madagaskar (2020),SEK,Lunch,-84 +Madagaskar (2020),SEK,Dinner,-84 +Makedonien (2018),SEK,Normalbelopp,297 +Makedonien (2018),SEK,Breakfast,-44.55 +Makedonien (2018),SEK,Lunch,-103.95 +Makedonien (2018),SEK,Dinner,-103.95 +Makedonien (2019),SEK,Normalbelopp,321 +Makedonien (2019),SEK,Breakfast,-48.15 +Makedonien (2019),SEK,Lunch,-112.35 +Makedonien (2019),SEK,Dinner,-112.35 +Makedonien (2020),SEK,Normalbelopp,327 +Makedonien (2020),SEK,Breakfast,-49.05 +Makedonien (2020),SEK,Lunch,-114.45 +Makedonien (2020),SEK,Dinner,-114.45 +Malawi (2018),SEK,Normalbelopp,230 +Malawi (2018),SEK,Breakfast,-34.5 +Malawi (2018),SEK,Lunch,-80.5 +Malawi (2018),SEK,Dinner,-80.5 +Malawi (2019),SEK,Normalbelopp,281 +Malawi (2019),SEK,Breakfast,-42.15 +Malawi (2019),SEK,Lunch,-98.35 +Malawi (2019),SEK,Dinner,-98.35 +Malawi (2020),SEK,Normalbelopp,385 +Malawi (2020),SEK,Breakfast,-57.75 +Malawi (2020),SEK,Lunch,-134.75 +Malawi (2020),SEK,Dinner,-134.75 +Malaysia (2018),SEK,Normalbelopp,274 +Malaysia (2018),SEK,Breakfast,-41.1 +Malaysia (2018),SEK,Lunch,-95.9 +Malaysia (2018),SEK,Dinner,-95.9 +Malaysia (2019),SEK,Normalbelopp,307 +Malaysia (2019),SEK,Breakfast,-46.05 +Malaysia (2019),SEK,Lunch,-107.45 +Malaysia (2019),SEK,Dinner,-107.45 +Malaysia (2020),SEK,Normalbelopp,330 +Malaysia (2020),SEK,Breakfast,-49.5 +Malaysia (2020),SEK,Lunch,-115.5 +Malaysia (2020),SEK,Dinner,-115.5 +Maldiverna (2018),SEK,Normalbelopp,339 +Maldiverna (2018),SEK,Breakfast,-50.85 +Maldiverna (2018),SEK,Lunch,-118.65 +Maldiverna (2018),SEK,Dinner,-118.65 +Maldiverna (2019),SEK,Normalbelopp,393 +Maldiverna (2019),SEK,Breakfast,-58.95 +Maldiverna (2019),SEK,Lunch,-137.55 +Maldiverna (2019),SEK,Dinner,-137.55 +Maldiverna (2020),SEK,Normalbelopp,433 +Maldiverna (2020),SEK,Breakfast,-64.95 +Maldiverna (2020),SEK,Lunch,-151.55 +Maldiverna (2020),SEK,Dinner,-151.55 +Mali (2018),SEK,Normalbelopp,440 +Mali (2018),SEK,Breakfast,-66 +Mali (2018),SEK,Lunch,-154 +Mali (2018),SEK,Dinner,-154 +Mali (2019),SEK,Normalbelopp,450 +Mali (2019),SEK,Breakfast,-67.5 +Mali (2019),SEK,Lunch,-157.5 +Mali (2019),SEK,Dinner,-157.5 +Mali (2020),SEK,Normalbelopp,454 +Mali (2020),SEK,Breakfast,-68.1 +Mali (2020),SEK,Lunch,-158.9 +Mali (2020),SEK,Dinner,-158.9 +Malta (2018),SEK,Normalbelopp,480 +Malta (2018),SEK,Breakfast,-72 +Malta (2018),SEK,Lunch,-168 +Malta (2018),SEK,Dinner,-168 +Malta (2019),SEK,Normalbelopp,510 +Malta (2019),SEK,Breakfast,-76.5 +Malta (2019),SEK,Lunch,-178.5 +Malta (2019),SEK,Dinner,-178.5 +Malta (2020),SEK,Normalbelopp,538 +Malta (2020),SEK,Breakfast,-80.7 +Malta (2020),SEK,Lunch,-188.3 +Malta (2020),SEK,Dinner,-188.3 +Marocko (2018),SEK,Normalbelopp,376 +Marocko (2018),SEK,Breakfast,-56.4 +Marocko (2018),SEK,Lunch,-131.6 +Marocko (2018),SEK,Dinner,-131.6 +Marocko (2019),SEK,Normalbelopp,414 +Marocko (2019),SEK,Breakfast,-62.1 +Marocko (2019),SEK,Lunch,-144.9 +Marocko (2019),SEK,Dinner,-144.9 +Marocko (2020),SEK,Normalbelopp,446 +Marocko (2020),SEK,Breakfast,-66.9 +Marocko (2020),SEK,Lunch,-156.1 +Marocko (2020),SEK,Dinner,-156.1 +Mauretanien (2018),SEK,Normalbelopp,319 +Mauretanien (2018),SEK,Breakfast,-47.85 +Mauretanien (2018),SEK,Lunch,-111.65 +Mauretanien (2018),SEK,Dinner,-111.65 +Mauretanien (2019),SEK,Normalbelopp,340 +Mauretanien (2019),SEK,Breakfast,-51 +Mauretanien (2019),SEK,Lunch,-119 +Mauretanien (2019),SEK,Dinner,-119 +Mauretanien (2020),SEK,Normalbelopp,353 +Mauretanien (2020),SEK,Breakfast,-52.95 +Mauretanien (2020),SEK,Lunch,-123.55 +Mauretanien (2020),SEK,Dinner,-123.55 +Mauritius (2018),SEK,Normalbelopp,399 +Mauritius (2018),SEK,Breakfast,-59.85 +Mauritius (2018),SEK,Lunch,-139.65 +Mauritius (2018),SEK,Dinner,-139.65 +Mauritius (2019),SEK,Normalbelopp,456 +Mauritius (2019),SEK,Breakfast,-68.4 +Mauritius (2019),SEK,Lunch,-159.6 +Mauritius (2019),SEK,Dinner,-159.6 +Mauritius (2020),SEK,Normalbelopp,465 +Mauritius (2020),SEK,Breakfast,-69.75 +Mauritius (2020),SEK,Lunch,-162.75 +Mauritius (2020),SEK,Dinner,-162.75 +Mexiko (2018),SEK,Normalbelopp,293 +Mexiko (2018),SEK,Breakfast,-43.95 +Mexiko (2018),SEK,Lunch,-102.55 +Mexiko (2018),SEK,Dinner,-102.55 +Mexiko (2019),SEK,Normalbelopp,301 +Mexiko (2019),SEK,Breakfast,-45.15 +Mexiko (2019),SEK,Lunch,-105.35 +Mexiko (2019),SEK,Dinner,-105.35 +Mexiko (2020),SEK,Normalbelopp,367 +Mexiko (2020),SEK,Breakfast,-55.05 +Mexiko (2020),SEK,Lunch,-128.45 +Mexiko (2020),SEK,Dinner,-128.45 +Mikronesien (2018),SEK,Normalbelopp,396 +Mikronesien (2018),SEK,Breakfast,-59.4 +Mikronesien (2018),SEK,Lunch,-138.6 +Mikronesien (2018),SEK,Dinner,-138.6 +Mikronesien (2019),SEK,Normalbelopp,443 +Mikronesien (2019),SEK,Breakfast,-66.45 +Mikronesien (2019),SEK,Lunch,-155.05 +Mikronesien (2019),SEK,Dinner,-155.05 +Mikronesien (2020),SEK,Normalbelopp,464 +Mikronesien (2020),SEK,Breakfast,-69.6 +Mikronesien (2020),SEK,Lunch,-162.4 +Mikronesien (2020),SEK,Dinner,-162.4 +Mocambique (2018),SEK,Normalbelopp,255 +Mocambique (2018),SEK,Breakfast,-38.25 +Mocambique (2018),SEK,Lunch,-89.25 +Mocambique (2018),SEK,Dinner,-89.25 +Mocambique (2019),SEK,Normalbelopp,288 +Mocambique (2019),SEK,Breakfast,-43.2 +Mocambique (2019),SEK,Lunch,-100.8 +Mocambique (2019),SEK,Dinner,-100.8 +Mocambique (2020),SEK,Normalbelopp,297 +Mocambique (2020),SEK,Breakfast,-44.55 +Mocambique (2020),SEK,Lunch,-103.95 +Mocambique (2020),SEK,Dinner,-103.95 +Moldavien (2018),SEK,Normalbelopp,230 +Moldavien (2018),SEK,Breakfast,-34.5 +Moldavien (2018),SEK,Lunch,-80.5 +Moldavien (2018),SEK,Dinner,-80.5 +Moldavien (2019),SEK,Normalbelopp,248 +Moldavien (2019),SEK,Breakfast,-37.2 +Moldavien (2019),SEK,Lunch,-86.8 +Moldavien (2019),SEK,Dinner,-86.8 +Moldavien (2020),SEK,Normalbelopp,285 +Moldavien (2020),SEK,Breakfast,-42.75 +Moldavien (2020),SEK,Lunch,-99.75 +Moldavien (2020),SEK,Dinner,-99.75 +Monaco (2018),SEK,Normalbelopp,818 +Monaco (2018),SEK,Breakfast,-122.7 +Monaco (2018),SEK,Lunch,-286.3 +Monaco (2018),SEK,Dinner,-286.3 +Monaco (2019),SEK,Normalbelopp,858 +Monaco (2019),SEK,Breakfast,-128.7 +Monaco (2019),SEK,Lunch,-300.3 +Monaco (2019),SEK,Dinner,-300.3 +Monaco (2020),SEK,Normalbelopp,906 +Monaco (2020),SEK,Breakfast,-135.9 +Monaco (2020),SEK,Lunch,-317.1 +Monaco (2020),SEK,Dinner,-317.1 +Mongoliet (2018),SEK,Normalbelopp,230 +Mongoliet (2018),SEK,Breakfast,-34.5 +Mongoliet (2018),SEK,Lunch,-80.5 +Mongoliet (2018),SEK,Dinner,-80.5 +Mongoliet (2019),SEK,Normalbelopp,280 +Mongoliet (2019),SEK,Breakfast,-42 +Mongoliet (2019),SEK,Lunch,-98 +Mongoliet (2019),SEK,Dinner,-98 +Mongoliet (2020),SEK,Normalbelopp,283 +Mongoliet (2020),SEK,Breakfast,-42.45 +Mongoliet (2020),SEK,Lunch,-99.05 +Mongoliet (2020),SEK,Dinner,-99.05 +Montenegro (2018),SEK,Normalbelopp,393 +Montenegro (2018),SEK,Breakfast,-58.95 +Montenegro (2018),SEK,Lunch,-137.55 +Montenegro (2018),SEK,Dinner,-137.55 +Montenegro (2019),SEK,Normalbelopp,423 +Montenegro (2019),SEK,Breakfast,-63.45 +Montenegro (2019),SEK,Lunch,-148.05 +Montenegro (2019),SEK,Dinner,-148.05 +Montenegro (2020),SEK,Normalbelopp,391 +Montenegro (2020),SEK,Breakfast,-58.65 +Montenegro (2020),SEK,Lunch,-136.85 +Montenegro (2020),SEK,Dinner,-136.85 +Myanmar (2018),SEK,Normalbelopp,315 +Myanmar (2018),SEK,Breakfast,-47.25 +Myanmar (2018),SEK,Lunch,-110.25 +Myanmar (2018),SEK,Dinner,-110.25 +Myanmar (2019),SEK,Normalbelopp,286 +Myanmar (2019),SEK,Breakfast,-42.9 +Myanmar (2019),SEK,Lunch,-100.1 +Myanmar (2019),SEK,Dinner,-100.1 +Myanmar (2020),SEK,Normalbelopp,318 +Myanmar (2020),SEK,Breakfast,-47.7 +Myanmar (2020),SEK,Lunch,-111.3 +Myanmar (2020),SEK,Dinner,-111.3 +Nederländerna (2018),SEK,Normalbelopp,554 +Nederländerna (2018),SEK,Breakfast,-83.1 +Nederländerna (2018),SEK,Lunch,-193.9 +Nederländerna (2018),SEK,Dinner,-193.9 +Nederländerna (2019),SEK,Normalbelopp,610 +Nederländerna (2019),SEK,Breakfast,-91.5 +Nederländerna (2019),SEK,Lunch,-213.5 +Nederländerna (2019),SEK,Dinner,-213.5 +Nederländerna (2020),SEK,Normalbelopp,648 +Nederländerna (2020),SEK,Breakfast,-97.2 +Nederländerna (2020),SEK,Lunch,-226.8 +Nederländerna (2020),SEK,Dinner,-226.8 +Nederländska Antillerna (2018),SEK,Normalbelopp,490 +Nederländska Antillerna (2018),SEK,Breakfast,-73.5 +Nederländska Antillerna (2018),SEK,Lunch,-171.5 +Nederländska Antillerna (2018),SEK,Dinner,-171.5 +Nederländska Antillerna (2019),SEK,Normalbelopp,544 +Nederländska Antillerna (2019),SEK,Breakfast,-81.6 +Nederländska Antillerna (2019),SEK,Lunch,-190.4 +Nederländska Antillerna (2019),SEK,Dinner,-190.4 +Nederländska Antillerna (2020),SEK,Normalbelopp,601 +Nederländska Antillerna (2020),SEK,Breakfast,-90.15 +Nederländska Antillerna (2020),SEK,Lunch,-210.35 +Nederländska Antillerna (2020),SEK,Dinner,-210.35 +Nepal (2018),SEK,Normalbelopp,268 +Nepal (2018),SEK,Breakfast,-40.2 +Nepal (2018),SEK,Lunch,-93.8 +Nepal (2018),SEK,Dinner,-93.8 +Nepal (2019),SEK,Normalbelopp,258 +Nepal (2019),SEK,Breakfast,-38.7 +Nepal (2019),SEK,Lunch,-90.3 +Nepal (2019),SEK,Dinner,-90.3 +Nepal (2020),SEK,Normalbelopp,287 +Nepal (2020),SEK,Breakfast,-43.05 +Nepal (2020),SEK,Lunch,-100.45 +Nepal (2020),SEK,Dinner,-100.45 +Nicaragua (2018),SEK,Normalbelopp,328 +Nicaragua (2018),SEK,Breakfast,-49.2 +Nicaragua (2018),SEK,Lunch,-114.8 +Nicaragua (2018),SEK,Dinner,-114.8 +Nicaragua (2019),SEK,Normalbelopp,334 +Nicaragua (2019),SEK,Breakfast,-50.1 +Nicaragua (2019),SEK,Lunch,-116.9 +Nicaragua (2019),SEK,Dinner,-116.9 +Nicaragua (2020),SEK,Normalbelopp,367 +Nicaragua (2020),SEK,Breakfast,-55.05 +Nicaragua (2020),SEK,Lunch,-128.45 +Nicaragua (2020),SEK,Dinner,-128.45 +Niger (2018),SEK,Normalbelopp,306 +Niger (2018),SEK,Breakfast,-45.9 +Niger (2018),SEK,Lunch,-107.1 +Niger (2018),SEK,Dinner,-107.1 +Niger (2019),SEK,Normalbelopp,339 +Niger (2019),SEK,Breakfast,-50.85 +Niger (2019),SEK,Lunch,-118.65 +Niger (2019),SEK,Dinner,-118.65 +Niger (2020),SEK,Normalbelopp,354 +Niger (2020),SEK,Breakfast,-53.1 +Niger (2020),SEK,Lunch,-123.9 +Niger (2020),SEK,Dinner,-123.9 +Nigeria (2018),SEK,Normalbelopp,418 +Nigeria (2018),SEK,Breakfast,-62.7 +Nigeria (2018),SEK,Lunch,-146.3 +Nigeria (2018),SEK,Dinner,-146.3 +Nigeria (2019),SEK,Normalbelopp,501 +Nigeria (2019),SEK,Breakfast,-75.15 +Nigeria (2019),SEK,Lunch,-175.35 +Nigeria (2019),SEK,Dinner,-175.35 +Nigeria (2020),SEK,Normalbelopp,549 +Nigeria (2020),SEK,Breakfast,-82.35 +Nigeria (2020),SEK,Lunch,-192.15 +Nigeria (2020),SEK,Dinner,-192.15 +Nordmakedonien - f.d. Makedonien (2020),SEK,Normalbelopp,327 +Nordmakedonien - f.d. Makedonien (2020),SEK,Breakfast,-49.05 +Nordmakedonien - f.d. Makedonien (2020),SEK,Lunch,-114.45 +Nordmakedonien - f.d. Makedonien (2020),SEK,Dinner,-114.45 +Norge (2018),SEK,Normalbelopp,823 +Norge (2018),SEK,Breakfast,-123.45 +Norge (2018),SEK,Lunch,-288.05 +Norge (2018),SEK,Dinner,-288.05 +Norge (2019),SEK,Normalbelopp,876 +Norge (2019),SEK,Breakfast,-131.4 +Norge (2019),SEK,Lunch,-306.6 +Norge (2019),SEK,Dinner,-306.6 +Norge (2020),SEK,Normalbelopp,893 +Norge (2020),SEK,Breakfast,-133.95 +Norge (2020),SEK,Lunch,-312.55 +Norge (2020),SEK,Dinner,-312.55 +Nya Zeeland (2018),SEK,Normalbelopp,538 +Nya Zeeland (2018),SEK,Breakfast,-80.7 +Nya Zeeland (2018),SEK,Lunch,-188.3 +Nya Zeeland (2018),SEK,Dinner,-188.3 +Nya Zeeland (2019),SEK,Normalbelopp,565 +Nya Zeeland (2019),SEK,Breakfast,-84.75 +Nya Zeeland (2019),SEK,Lunch,-197.75 +Nya Zeeland (2019),SEK,Dinner,-197.75 +Nya Zeeland (2020),SEK,Normalbelopp,585 +Nya Zeeland (2020),SEK,Breakfast,-87.75 +Nya Zeeland (2020),SEK,Lunch,-204.75 +Nya Zeeland (2020),SEK,Dinner,-204.75 +Oman (2018),SEK,Normalbelopp,685 +Oman (2018),SEK,Breakfast,-102.75 +Oman (2018),SEK,Lunch,-239.75 +Oman (2018),SEK,Dinner,-239.75 +Oman (2019),SEK,Normalbelopp,748 +Oman (2019),SEK,Breakfast,-112.2 +Oman (2019),SEK,Lunch,-261.8 +Oman (2019),SEK,Dinner,-261.8 +Oman (2020),SEK,Normalbelopp,777 +Oman (2020),SEK,Breakfast,-116.55 +Oman (2020),SEK,Lunch,-271.95 +Oman (2020),SEK,Dinner,-271.95 +Österrike (2018),SEK,Normalbelopp,583 +Österrike (2018),SEK,Breakfast,-87.45 +Österrike (2018),SEK,Lunch,-204.05 +Österrike (2018),SEK,Dinner,-204.05 +Österrike (2019),SEK,Normalbelopp,616 +Österrike (2019),SEK,Breakfast,-92.4 +Österrike (2019),SEK,Lunch,-215.6 +Österrike (2019),SEK,Dinner,-215.6 +Österrike (2020),SEK,Normalbelopp,641 +Österrike (2020),SEK,Breakfast,-96.15 +Österrike (2020),SEK,Lunch,-224.35 +Österrike (2020),SEK,Dinner,-224.35 +Övriga länder och områden (2018),SEK,Normalbelopp,357 +Övriga länder och områden (2018),SEK,Breakfast,-53.55 +Övriga länder och områden (2018),SEK,Lunch,-124.95 +Övriga länder och områden (2018),SEK,Dinner,-124.95 +Övriga länder och områden (2019),SEK,Normalbelopp,369 +Övriga länder och områden (2019),SEK,Breakfast,-55.35 +Övriga länder och områden (2019),SEK,Lunch,-129.15 +Övriga länder och områden (2019),SEK,Dinner,-129.15 +Övriga länder och områden (2020),SEK,Normalbelopp,392 +Övriga länder och områden (2020),SEK,Breakfast,-58.8 +Övriga länder och områden (2020),SEK,Lunch,-137.2 +Övriga länder och områden (2020),SEK,Dinner,-137.2 +Pakistan (2018),SEK,Normalbelopp,296 +Pakistan (2018),SEK,Breakfast,-44.4 +Pakistan (2018),SEK,Lunch,-103.6 +Pakistan (2018),SEK,Dinner,-103.6 +Pakistan (2019),SEK,Normalbelopp,230 +Pakistan (2019),SEK,Breakfast,-34.5 +Pakistan (2019),SEK,Lunch,-80.5 +Pakistan (2019),SEK,Dinner,-80.5 +Pakistan (2020),SEK,Normalbelopp,240 +Pakistan (2020),SEK,Breakfast,-36 +Pakistan (2020),SEK,Lunch,-84 +Pakistan (2020),SEK,Dinner,-84 +Panama (2018),SEK,Normalbelopp,444 +Panama (2018),SEK,Breakfast,-66.6 +Panama (2018),SEK,Lunch,-155.4 +Panama (2018),SEK,Dinner,-155.4 +Panama (2019),SEK,Normalbelopp,505 +Panama (2019),SEK,Breakfast,-75.75 +Panama (2019),SEK,Lunch,-176.75 +Panama (2019),SEK,Dinner,-176.75 +Panama (2020),SEK,Normalbelopp,564 +Panama (2020),SEK,Breakfast,-84.6 +Panama (2020),SEK,Lunch,-197.4 +Panama (2020),SEK,Dinner,-197.4 +Papua Nya Guinea (2018),SEK,Normalbelopp,452 +Papua Nya Guinea (2018),SEK,Breakfast,-67.8 +Papua Nya Guinea (2018),SEK,Lunch,-158.2 +Papua Nya Guinea (2018),SEK,Dinner,-158.2 +Papua Nya Guinea (2019),SEK,Normalbelopp,487 +Papua Nya Guinea (2019),SEK,Breakfast,-73.05 +Papua Nya Guinea (2019),SEK,Lunch,-170.45 +Papua Nya Guinea (2019),SEK,Dinner,-170.45 +Papua Nya Guinea (2020),SEK,Normalbelopp,515 +Papua Nya Guinea (2020),SEK,Breakfast,-77.25 +Papua Nya Guinea (2020),SEK,Lunch,-180.25 +Papua Nya Guinea (2020),SEK,Dinner,-180.25 +Paraguay (2018),SEK,Normalbelopp,298 +Paraguay (2018),SEK,Breakfast,-44.7 +Paraguay (2018),SEK,Lunch,-104.3 +Paraguay (2018),SEK,Dinner,-104.3 +Paraguay (2019),SEK,Normalbelopp,316 +Paraguay (2019),SEK,Breakfast,-47.4 +Paraguay (2019),SEK,Lunch,-110.6 +Paraguay (2019),SEK,Dinner,-110.6 +Paraguay (2020),SEK,Normalbelopp,314 +Paraguay (2020),SEK,Breakfast,-47.1 +Paraguay (2020),SEK,Lunch,-109.9 +Paraguay (2020),SEK,Dinner,-109.9 +Peru (2018),SEK,Normalbelopp,457 +Peru (2018),SEK,Breakfast,-68.55 +Peru (2018),SEK,Lunch,-159.95 +Peru (2018),SEK,Dinner,-159.95 +Peru (2019),SEK,Normalbelopp,481 +Peru (2019),SEK,Breakfast,-72.15 +Peru (2019),SEK,Lunch,-168.35 +Peru (2019),SEK,Dinner,-168.35 +Peru (2020),SEK,Normalbelopp,511 +Peru (2020),SEK,Breakfast,-76.65 +Peru (2020),SEK,Lunch,-178.85 +Peru (2020),SEK,Dinner,-178.85 +Polen (2018),SEK,Normalbelopp,411 +Polen (2018),SEK,Breakfast,-61.65 +Polen (2018),SEK,Lunch,-143.85 +Polen (2018),SEK,Dinner,-143.85 +Polen (2019),SEK,Normalbelopp,436 +Polen (2019),SEK,Breakfast,-65.4 +Polen (2019),SEK,Lunch,-152.6 +Polen (2019),SEK,Dinner,-152.6 +Polen (2020),SEK,Normalbelopp,461 +Polen (2020),SEK,Breakfast,-69.15 +Polen (2020),SEK,Lunch,-161.35 +Polen (2020),SEK,Dinner,-161.35 +Portugal (2018),SEK,Normalbelopp,432 +Portugal (2018),SEK,Breakfast,-64.8 +Portugal (2018),SEK,Lunch,-151.2 +Portugal (2018),SEK,Dinner,-151.2 +Portugal (2019),SEK,Normalbelopp,461 +Portugal (2019),SEK,Breakfast,-69.15 +Portugal (2019),SEK,Lunch,-161.35 +Portugal (2019),SEK,Dinner,-161.35 +Portugal (2020),SEK,Normalbelopp,486 +Portugal (2020),SEK,Breakfast,-72.9 +Portugal (2020),SEK,Lunch,-170.1 +Portugal (2020),SEK,Dinner,-170.1 +Puerto Rico (2018),SEK,Normalbelopp,689 +Puerto Rico (2018),SEK,Breakfast,-103.35 +Puerto Rico (2018),SEK,Lunch,-241.15 +Puerto Rico (2018),SEK,Dinner,-241.15 +Puerto Rico (2019),SEK,Normalbelopp,762 +Puerto Rico (2019),SEK,Breakfast,-114.3 +Puerto Rico (2019),SEK,Lunch,-266.7 +Puerto Rico (2019),SEK,Dinner,-266.7 +Puerto Rico (2020),SEK,Normalbelopp,851 +Puerto Rico (2020),SEK,Breakfast,-127.65 +Puerto Rico (2020),SEK,Lunch,-297.85 +Puerto Rico (2020),SEK,Dinner,-297.85 +Qatar (2018),SEK,Normalbelopp,645 +Qatar (2018),SEK,Breakfast,-96.75 +Qatar (2018),SEK,Lunch,-225.75 +Qatar (2018),SEK,Dinner,-225.75 +Qatar (2019),SEK,Normalbelopp,716 +Qatar (2019),SEK,Breakfast,-107.4 +Qatar (2019),SEK,Lunch,-250.6 +Qatar (2019),SEK,Dinner,-250.6 +Qatar (2020),SEK,Normalbelopp,766 +Qatar (2020),SEK,Breakfast,-114.9 +Qatar (2020),SEK,Lunch,-268.1 +Qatar (2020),SEK,Dinner,-268.1 +Rumänien (2018),SEK,Normalbelopp,312 +Rumänien (2018),SEK,Breakfast,-46.8 +Rumänien (2018),SEK,Lunch,-109.2 +Rumänien (2018),SEK,Dinner,-109.2 +Rumänien (2019),SEK,Normalbelopp,332 +Rumänien (2019),SEK,Breakfast,-49.8 +Rumänien (2019),SEK,Lunch,-116.2 +Rumänien (2019),SEK,Dinner,-116.2 +Rumänien (2020),SEK,Normalbelopp,337 +Rumänien (2020),SEK,Breakfast,-50.55 +Rumänien (2020),SEK,Lunch,-117.95 +Rumänien (2020),SEK,Dinner,-117.95 +Rwanda (2018),SEK,Normalbelopp,296 +Rwanda (2018),SEK,Breakfast,-44.4 +Rwanda (2018),SEK,Lunch,-103.6 +Rwanda (2018),SEK,Dinner,-103.6 +Rwanda (2019),SEK,Normalbelopp,333 +Rwanda (2019),SEK,Breakfast,-49.95 +Rwanda (2019),SEK,Lunch,-116.55 +Rwanda (2019),SEK,Dinner,-116.55 +Rwanda (2020),SEK,Normalbelopp,332 +Rwanda (2020),SEK,Breakfast,-49.8 +Rwanda (2020),SEK,Lunch,-116.2 +Rwanda (2020),SEK,Dinner,-116.2 +Ryssland (2018),SEK,Normalbelopp,470 +Ryssland (2018),SEK,Breakfast,-70.5 +Ryssland (2018),SEK,Lunch,-164.5 +Ryssland (2018),SEK,Dinner,-164.5 +Ryssland (2019),SEK,Normalbelopp,455 +Ryssland (2019),SEK,Breakfast,-68.25 +Ryssland (2019),SEK,Lunch,-159.25 +Ryssland (2019),SEK,Dinner,-159.25 +Ryssland (2020),SEK,Normalbelopp,520 +Ryssland (2020),SEK,Breakfast,-78 +Ryssland (2020),SEK,Lunch,-182 +Ryssland (2020),SEK,Dinner,-182 +Saint Lucia (2018),SEK,Normalbelopp,524 +Saint Lucia (2018),SEK,Breakfast,-78.6 +Saint Lucia (2018),SEK,Lunch,-183.4 +Saint Lucia (2018),SEK,Dinner,-183.4 +Saint Lucia (2019),SEK,Normalbelopp,555 +Saint Lucia (2019),SEK,Breakfast,-83.25 +Saint Lucia (2019),SEK,Lunch,-194.25 +Saint Lucia (2019),SEK,Dinner,-194.25 +Saint Lucia (2020),SEK,Normalbelopp,573 +Saint Lucia (2020),SEK,Breakfast,-85.95 +Saint Lucia (2020),SEK,Lunch,-200.55 +Saint Lucia (2020),SEK,Dinner,-200.55 +Saint Vincent och Grenadinerna (2018),SEK,Normalbelopp,460 +Saint Vincent och Grenadinerna (2018),SEK,Breakfast,-69 +Saint Vincent och Grenadinerna (2018),SEK,Lunch,-161 +Saint Vincent och Grenadinerna (2018),SEK,Dinner,-161 +Saint Vincent och Grenadinerna (2019),SEK,Normalbelopp,502 +Saint Vincent och Grenadinerna (2019),SEK,Breakfast,-75.3 +Saint Vincent och Grenadinerna (2019),SEK,Lunch,-175.7 +Saint Vincent och Grenadinerna (2019),SEK,Dinner,-175.7 +Saint Vincent och Grenadinerna (2020),SEK,Normalbelopp,516 +Saint Vincent och Grenadinerna (2020),SEK,Breakfast,-77.4 +Saint Vincent och Grenadinerna (2020),SEK,Lunch,-180.6 +Saint Vincent och Grenadinerna (2020),SEK,Dinner,-180.6 +Samoa - Självständiga staten (2018),SEK,Normalbelopp,479 +Samoa - Självständiga staten (2018),SEK,Breakfast,-71.85 +Samoa - Självständiga staten (2018),SEK,Lunch,-167.65 +Samoa - Självständiga staten (2018),SEK,Dinner,-167.65 +Samoa - Självständiga staten (2019),SEK,Normalbelopp,513 +Samoa - Självständiga staten (2019),SEK,Breakfast,-76.95 +Samoa - Självständiga staten (2019),SEK,Lunch,-179.55 +Samoa - Självständiga staten (2019),SEK,Dinner,-179.55 +Samoa - Självständiga staten (2020),SEK,Normalbelopp,572 +Samoa - Självständiga staten (2020),SEK,Breakfast,-85.8 +Samoa - Självständiga staten (2020),SEK,Lunch,-200.2 +Samoa - Självständiga staten (2020),SEK,Dinner,-200.2 +San Marino (2018),SEK,Normalbelopp,540 +San Marino (2018),SEK,Breakfast,-81 +San Marino (2018),SEK,Lunch,-189 +San Marino (2018),SEK,Dinner,-189 +San Marino (2019),SEK,Normalbelopp,590 +San Marino (2019),SEK,Breakfast,-88.5 +San Marino (2019),SEK,Lunch,-206.5 +San Marino (2019),SEK,Dinner,-206.5 +San Marino (2020),SEK,Normalbelopp,627 +San Marino (2020),SEK,Breakfast,-94.05 +San Marino (2020),SEK,Lunch,-219.45 +San Marino (2020),SEK,Dinner,-219.45 +Saudiarabien (2018),SEK,Normalbelopp,568 +Saudiarabien (2018),SEK,Breakfast,-85.2 +Saudiarabien (2018),SEK,Lunch,-198.8 +Saudiarabien (2018),SEK,Dinner,-198.8 +Saudiarabien (2019),SEK,Normalbelopp,652 +Saudiarabien (2019),SEK,Breakfast,-97.8 +Saudiarabien (2019),SEK,Lunch,-228.2 +Saudiarabien (2019),SEK,Dinner,-228.2 +Saudiarabien (2020),SEK,Normalbelopp,742 +Saudiarabien (2020),SEK,Breakfast,-111.3 +Saudiarabien (2020),SEK,Lunch,-259.7 +Saudiarabien (2020),SEK,Dinner,-259.7 +Schweiz (2018),SEK,Normalbelopp,819 +Schweiz (2018),SEK,Breakfast,-122.85 +Schweiz (2018),SEK,Lunch,-286.65 +Schweiz (2018),SEK,Dinner,-286.65 +Schweiz (2019),SEK,Normalbelopp,888 +Schweiz (2019),SEK,Breakfast,-133.2 +Schweiz (2019),SEK,Lunch,-310.8 +Schweiz (2019),SEK,Dinner,-310.8 +Schweiz (2020),SEK,Normalbelopp,979 +Schweiz (2020),SEK,Breakfast,-146.85 +Schweiz (2020),SEK,Lunch,-342.65 +Schweiz (2020),SEK,Dinner,-342.65 +Senegal (2018),SEK,Normalbelopp,511 +Senegal (2018),SEK,Breakfast,-76.65 +Senegal (2018),SEK,Lunch,-178.85 +Senegal (2018),SEK,Dinner,-178.85 +Senegal (2019),SEK,Normalbelopp,539 +Senegal (2019),SEK,Breakfast,-80.85 +Senegal (2019),SEK,Lunch,-188.65 +Senegal (2019),SEK,Dinner,-188.65 +Senegal (2020),SEK,Normalbelopp,563 +Senegal (2020),SEK,Breakfast,-84.45 +Senegal (2020),SEK,Lunch,-197.05 +Senegal (2020),SEK,Dinner,-197.05 +Serbien (2018),SEK,Normalbelopp,362 +Serbien (2018),SEK,Breakfast,-54.3 +Serbien (2018),SEK,Lunch,-126.7 +Serbien (2018),SEK,Dinner,-126.7 +Serbien (2019),SEK,Normalbelopp,388 +Serbien (2019),SEK,Breakfast,-58.2 +Serbien (2019),SEK,Lunch,-135.8 +Serbien (2019),SEK,Dinner,-135.8 +Serbien (2020),SEK,Normalbelopp,395 +Serbien (2020),SEK,Breakfast,-59.25 +Serbien (2020),SEK,Lunch,-138.25 +Serbien (2020),SEK,Dinner,-138.25 +Seychellerna (2018),SEK,Normalbelopp,542 +Seychellerna (2018),SEK,Breakfast,-81.3 +Seychellerna (2018),SEK,Lunch,-189.7 +Seychellerna (2018),SEK,Dinner,-189.7 +Seychellerna (2019),SEK,Normalbelopp,620 +Seychellerna (2019),SEK,Breakfast,-93 +Seychellerna (2019),SEK,Lunch,-217 +Seychellerna (2019),SEK,Dinner,-217 +Seychellerna (2020),SEK,Normalbelopp,696 +Seychellerna (2020),SEK,Breakfast,-104.4 +Seychellerna (2020),SEK,Lunch,-243.6 +Seychellerna (2020),SEK,Dinner,-243.6 +Sierra Leone (2018),SEK,Normalbelopp,287 +Sierra Leone (2018),SEK,Breakfast,-43.05 +Sierra Leone (2018),SEK,Lunch,-100.45 +Sierra Leone (2018),SEK,Dinner,-100.45 +Sierra Leone (2019),SEK,Normalbelopp,328 +Sierra Leone (2019),SEK,Breakfast,-49.2 +Sierra Leone (2019),SEK,Lunch,-114.8 +Sierra Leone (2019),SEK,Dinner,-114.8 +Sierra Leone (2020),SEK,Normalbelopp,351 +Sierra Leone (2020),SEK,Breakfast,-52.65 +Sierra Leone (2020),SEK,Lunch,-122.85 +Sierra Leone (2020),SEK,Dinner,-122.85 +Singapore (2018),SEK,Normalbelopp,576 +Singapore (2018),SEK,Breakfast,-86.4 +Singapore (2018),SEK,Lunch,-201.6 +Singapore (2018),SEK,Dinner,-201.6 +Singapore (2019),SEK,Normalbelopp,632 +Singapore (2019),SEK,Breakfast,-94.8 +Singapore (2019),SEK,Lunch,-221.2 +Singapore (2019),SEK,Dinner,-221.2 +Singapore (2020),SEK,Normalbelopp,690 +Singapore (2020),SEK,Breakfast,-103.5 +Singapore (2020),SEK,Lunch,-241.5 +Singapore (2020),SEK,Dinner,-241.5 +Slovakien (2018),SEK,Normalbelopp,451 +Slovakien (2018),SEK,Breakfast,-67.65 +Slovakien (2018),SEK,Lunch,-157.85 +Slovakien (2018),SEK,Dinner,-157.85 +Slovakien (2019),SEK,Normalbelopp,479 +Slovakien (2019),SEK,Breakfast,-71.85 +Slovakien (2019),SEK,Lunch,-167.65 +Slovakien (2019),SEK,Dinner,-167.65 +Slovakien (2020),SEK,Normalbelopp,519 +Slovakien (2020),SEK,Breakfast,-77.85 +Slovakien (2020),SEK,Lunch,-181.65 +Slovakien (2020),SEK,Dinner,-181.65 +Slovenien (2018),SEK,Normalbelopp,463 +Slovenien (2018),SEK,Breakfast,-69.45 +Slovenien (2018),SEK,Lunch,-162.05 +Slovenien (2018),SEK,Dinner,-162.05 +Slovenien (2019),SEK,Normalbelopp,503 +Slovenien (2019),SEK,Breakfast,-75.45 +Slovenien (2019),SEK,Lunch,-176.05 +Slovenien (2019),SEK,Dinner,-176.05 +Slovenien (2020),SEK,Normalbelopp,529 +Slovenien (2020),SEK,Breakfast,-79.35 +Slovenien (2020),SEK,Lunch,-185.15 +Slovenien (2020),SEK,Dinner,-185.15 +Spanien (2018),SEK,Normalbelopp,513 +Spanien (2018),SEK,Breakfast,-76.95 +Spanien (2018),SEK,Lunch,-179.55 +Spanien (2018),SEK,Dinner,-179.55 +Spanien (2019),SEK,Normalbelopp,558 +Spanien (2019),SEK,Breakfast,-83.7 +Spanien (2019),SEK,Lunch,-195.3 +Spanien (2019),SEK,Dinner,-195.3 +Spanien (2020),SEK,Normalbelopp,615 +Spanien (2020),SEK,Breakfast,-92.25 +Spanien (2020),SEK,Lunch,-215.25 +Spanien (2020),SEK,Dinner,-215.25 +Sri Lanka (2018),SEK,Normalbelopp,283 +Sri Lanka (2018),SEK,Breakfast,-42.45 +Sri Lanka (2018),SEK,Lunch,-99.05 +Sri Lanka (2018),SEK,Dinner,-99.05 +Sri Lanka (2019),SEK,Normalbelopp,263 +Sri Lanka (2019),SEK,Breakfast,-39.45 +Sri Lanka (2019),SEK,Lunch,-92.05 +Sri Lanka (2019),SEK,Dinner,-92.05 +Sri Lanka (2020),SEK,Normalbelopp,272 +Sri Lanka (2020),SEK,Breakfast,-40.8 +Sri Lanka (2020),SEK,Lunch,-95.2 +Sri Lanka (2020),SEK,Dinner,-95.2 +Storbritannien och Nordirland (2018),SEK,Normalbelopp,655 +Storbritannien och Nordirland (2018),SEK,Breakfast,-98.25 +Storbritannien och Nordirland (2018),SEK,Lunch,-229.25 +Storbritannien och Nordirland (2018),SEK,Dinner,-229.25 +Storbritannien och Nordirland (2019),SEK,Normalbelopp,689 +Storbritannien och Nordirland (2019),SEK,Breakfast,-103.35 +Storbritannien och Nordirland (2019),SEK,Lunch,-241.15 +Storbritannien och Nordirland (2019),SEK,Dinner,-241.15 +Storbritannien och Nordirland (2020),SEK,Normalbelopp,746 +Storbritannien och Nordirland (2020),SEK,Breakfast,-111.9 +Storbritannien och Nordirland (2020),SEK,Lunch,-261.1 +Storbritannien och Nordirland (2020),SEK,Dinner,-261.1 +Sudan (2018),SEK,Normalbelopp,507 +Sudan (2018),SEK,Breakfast,-76.05 +Sudan (2018),SEK,Lunch,-177.45 +Sudan (2018),SEK,Dinner,-177.45 +Sudan (2019),SEK,Normalbelopp,230 +Sudan (2019),SEK,Breakfast,-34.5 +Sudan (2019),SEK,Lunch,-80.5 +Sudan (2019),SEK,Dinner,-80.5 +Sudan (2020),SEK,Normalbelopp,240 +Sudan (2020),SEK,Breakfast,-36 +Sudan (2020),SEK,Lunch,-84 +Sudan (2020),SEK,Dinner,-84 +Swaziland (2018),SEK,Normalbelopp,230 +Swaziland (2018),SEK,Breakfast,-34.5 +Swaziland (2018),SEK,Lunch,-80.5 +Swaziland (2018),SEK,Dinner,-80.5 +Swaziland (2019),SEK,Normalbelopp,230 +Swaziland (2019),SEK,Breakfast,-34.5 +Swaziland (2019),SEK,Lunch,-80.5 +Swaziland (2019),SEK,Dinner,-80.5 +Swaziland (2020),SEK,Normalbelopp,240 +Swaziland (2020),SEK,Breakfast,-36 +Swaziland (2020),SEK,Lunch,-84 +Swaziland (2020),SEK,Dinner,-84 +Sydafrika (2018),SEK,Normalbelopp,249 +Sydafrika (2018),SEK,Breakfast,-37.35 +Sydafrika (2018),SEK,Lunch,-87.15 +Sydafrika (2018),SEK,Dinner,-87.15 +Sydafrika (2019),SEK,Normalbelopp,262 +Sydafrika (2019),SEK,Breakfast,-39.3 +Sydafrika (2019),SEK,Lunch,-91.7 +Sydafrika (2019),SEK,Dinner,-91.7 +Sydafrika (2020),SEK,Normalbelopp,286 +Sydafrika (2020),SEK,Breakfast,-42.9 +Sydafrika (2020),SEK,Lunch,-100.1 +Sydafrika (2020),SEK,Dinner,-100.1 +Sydkorea (2018),SEK,Normalbelopp,624 +Sydkorea (2018),SEK,Breakfast,-93.6 +Sydkorea (2018),SEK,Lunch,-218.4 +Sydkorea (2018),SEK,Dinner,-218.4 +Sydkorea (2019),SEK,Normalbelopp,675 +Sydkorea (2019),SEK,Breakfast,-101.25 +Sydkorea (2019),SEK,Lunch,-236.25 +Sydkorea (2019),SEK,Dinner,-236.25 +Sydkorea (2020),SEK,Normalbelopp,696 +Sydkorea (2020),SEK,Breakfast,-104.4 +Sydkorea (2020),SEK,Lunch,-243.6 +Sydkorea (2020),SEK,Dinner,-243.6 +Taiwan (2018),SEK,Normalbelopp,465 +Taiwan (2018),SEK,Breakfast,-69.75 +Taiwan (2018),SEK,Lunch,-162.75 +Taiwan (2018),SEK,Dinner,-162.75 +Taiwan (2019),SEK,Normalbelopp,505 +Taiwan (2019),SEK,Breakfast,-75.75 +Taiwan (2019),SEK,Lunch,-176.75 +Taiwan (2019),SEK,Dinner,-176.75 +Taiwan (2020),SEK,Normalbelopp,546 +Taiwan (2020),SEK,Breakfast,-81.9 +Taiwan (2020),SEK,Lunch,-191.1 +Taiwan (2020),SEK,Dinner,-191.1 +Tanzania (2018),SEK,Normalbelopp,328 +Tanzania (2018),SEK,Breakfast,-49.2 +Tanzania (2018),SEK,Lunch,-114.8 +Tanzania (2018),SEK,Dinner,-114.8 +Tanzania (2019),SEK,Normalbelopp,349 +Tanzania (2019),SEK,Breakfast,-52.35 +Tanzania (2019),SEK,Lunch,-122.15 +Tanzania (2019),SEK,Dinner,-122.15 +Tanzania (2020),SEK,Normalbelopp,360 +Tanzania (2020),SEK,Breakfast,-54 +Tanzania (2020),SEK,Lunch,-126 +Tanzania (2020),SEK,Dinner,-126 +Thailand (2018),SEK,Normalbelopp,475 +Thailand (2018),SEK,Breakfast,-71.25 +Thailand (2018),SEK,Lunch,-166.25 +Thailand (2018),SEK,Dinner,-166.25 +Thailand (2019),SEK,Normalbelopp,525 +Thailand (2019),SEK,Breakfast,-78.75 +Thailand (2019),SEK,Lunch,-183.75 +Thailand (2019),SEK,Dinner,-183.75 +Thailand (2020),SEK,Normalbelopp,617 +Thailand (2020),SEK,Breakfast,-92.55 +Thailand (2020),SEK,Lunch,-215.95 +Thailand (2020),SEK,Dinner,-215.95 +Tjeckien (2018),SEK,Normalbelopp,388 +Tjeckien (2018),SEK,Breakfast,-58.2 +Tjeckien (2018),SEK,Lunch,-135.8 +Tjeckien (2018),SEK,Dinner,-135.8 +Tjeckien (2019),SEK,Normalbelopp,417 +Tjeckien (2019),SEK,Breakfast,-62.55 +Tjeckien (2019),SEK,Lunch,-145.95 +Tjeckien (2019),SEK,Dinner,-145.95 +Tjeckien (2020),SEK,Normalbelopp,436 +Tjeckien (2020),SEK,Breakfast,-65.4 +Tjeckien (2020),SEK,Lunch,-152.6 +Tjeckien (2020),SEK,Dinner,-152.6 +Togo (2018),SEK,Normalbelopp,438 +Togo (2018),SEK,Breakfast,-65.7 +Togo (2018),SEK,Lunch,-153.3 +Togo (2018),SEK,Dinner,-153.3 +Togo (2019),SEK,Normalbelopp,457 +Togo (2019),SEK,Breakfast,-68.55 +Togo (2019),SEK,Lunch,-159.95 +Togo (2019),SEK,Dinner,-159.95 +Togo (2020),SEK,Normalbelopp,482 +Togo (2020),SEK,Breakfast,-72.3 +Togo (2020),SEK,Lunch,-168.7 +Togo (2020),SEK,Dinner,-168.7 +Tonga (2018),SEK,Normalbelopp,380 +Tonga (2018),SEK,Breakfast,-57 +Tonga (2018),SEK,Lunch,-133 +Tonga (2018),SEK,Dinner,-133 +Tonga (2019),SEK,Normalbelopp,435 +Tonga (2019),SEK,Breakfast,-65.25 +Tonga (2019),SEK,Lunch,-152.25 +Tonga (2019),SEK,Dinner,-152.25 +Tonga (2020),SEK,Normalbelopp,455 +Tonga (2020),SEK,Breakfast,-68.25 +Tonga (2020),SEK,Lunch,-159.25 +Tonga (2020),SEK,Dinner,-159.25 +Trinidad och Tobago (2018),SEK,Normalbelopp,674 +Trinidad och Tobago (2018),SEK,Breakfast,-101.1 +Trinidad och Tobago (2018),SEK,Lunch,-235.9 +Trinidad och Tobago (2018),SEK,Dinner,-235.9 +Trinidad och Tobago (2019),SEK,Normalbelopp,728 +Trinidad och Tobago (2019),SEK,Breakfast,-109.2 +Trinidad och Tobago (2019),SEK,Lunch,-254.8 +Trinidad och Tobago (2019),SEK,Dinner,-254.8 +Trinidad och Tobago (2020),SEK,Normalbelopp,757 +Trinidad och Tobago (2020),SEK,Breakfast,-113.55 +Trinidad och Tobago (2020),SEK,Lunch,-264.95 +Trinidad och Tobago (2020),SEK,Dinner,-264.95 +Tunisien (2018),SEK,Normalbelopp,282 +Tunisien (2018),SEK,Breakfast,-42.3 +Tunisien (2018),SEK,Lunch,-98.7 +Tunisien (2018),SEK,Dinner,-98.7 +Tunisien (2019),SEK,Normalbelopp,240 +Tunisien (2019),SEK,Breakfast,-36 +Tunisien (2019),SEK,Lunch,-84 +Tunisien (2019),SEK,Dinner,-84 +Tunisien (2020),SEK,Normalbelopp,251 +Tunisien (2020),SEK,Breakfast,-37.65 +Tunisien (2020),SEK,Lunch,-87.85 +Tunisien (2020),SEK,Dinner,-87.85 +Turkiet (2018),SEK,Normalbelopp,274 +Turkiet (2018),SEK,Breakfast,-41.1 +Turkiet (2018),SEK,Lunch,-95.9 +Turkiet (2018),SEK,Dinner,-95.9 +Turkiet (2019),SEK,Normalbelopp,230 +Turkiet (2019),SEK,Breakfast,-34.5 +Turkiet (2019),SEK,Lunch,-80.5 +Turkiet (2019),SEK,Dinner,-80.5 +Turkiet (2020),SEK,Normalbelopp,251 +Turkiet (2020),SEK,Breakfast,-37.65 +Turkiet (2020),SEK,Lunch,-87.85 +Turkiet (2020),SEK,Dinner,-87.85 +Turkmenistan (2018),SEK,Normalbelopp,395 +Turkmenistan (2018),SEK,Breakfast,-59.25 +Turkmenistan (2018),SEK,Lunch,-138.25 +Turkmenistan (2018),SEK,Dinner,-138.25 +Turkmenistan (2019),SEK,Normalbelopp,473 +Turkmenistan (2019),SEK,Breakfast,-70.95 +Turkmenistan (2019),SEK,Lunch,-165.55 +Turkmenistan (2019),SEK,Dinner,-165.55 +Turkmenistan (2020),SEK,Normalbelopp,560 +Turkmenistan (2020),SEK,Breakfast,-84 +Turkmenistan (2020),SEK,Lunch,-196 +Turkmenistan (2020),SEK,Dinner,-196 +Tyskland (2018),SEK,Normalbelopp,620 +Tyskland (2018),SEK,Breakfast,-93 +Tyskland (2018),SEK,Lunch,-217 +Tyskland (2018),SEK,Dinner,-217 +Tyskland (2019),SEK,Normalbelopp,646 +Tyskland (2019),SEK,Breakfast,-96.9 +Tyskland (2019),SEK,Lunch,-226.1 +Tyskland (2019),SEK,Dinner,-226.1 +Tyskland (2020),SEK,Normalbelopp,668 +Tyskland (2020),SEK,Breakfast,-100.2 +Tyskland (2020),SEK,Lunch,-233.8 +Tyskland (2020),SEK,Dinner,-233.8 +Uganda (2018),SEK,Normalbelopp,243 +Uganda (2018),SEK,Breakfast,-36.45 +Uganda (2018),SEK,Lunch,-85.05 +Uganda (2018),SEK,Dinner,-85.05 +Uganda (2019),SEK,Normalbelopp,267 +Uganda (2019),SEK,Breakfast,-40.05 +Uganda (2019),SEK,Lunch,-93.45 +Uganda (2019),SEK,Dinner,-93.45 +Uganda (2020),SEK,Normalbelopp,321 +Uganda (2020),SEK,Breakfast,-48.15 +Uganda (2020),SEK,Lunch,-112.35 +Uganda (2020),SEK,Dinner,-112.35 +Ukraina (2018),SEK,Normalbelopp,257 +Ukraina (2018),SEK,Breakfast,-38.55 +Ukraina (2018),SEK,Lunch,-89.95 +Ukraina (2018),SEK,Dinner,-89.95 +Ukraina (2019),SEK,Normalbelopp,278 +Ukraina (2019),SEK,Breakfast,-41.7 +Ukraina (2019),SEK,Lunch,-97.3 +Ukraina (2019),SEK,Dinner,-97.3 +Ukraina (2020),SEK,Normalbelopp,356 +Ukraina (2020),SEK,Breakfast,-53.4 +Ukraina (2020),SEK,Lunch,-124.6 +Ukraina (2020),SEK,Dinner,-124.6 +Ungern (2018),SEK,Normalbelopp,393 +Ungern (2018),SEK,Breakfast,-58.95 +Ungern (2018),SEK,Lunch,-137.55 +Ungern (2018),SEK,Dinner,-137.55 +Ungern (2019),SEK,Normalbelopp,417 +Ungern (2019),SEK,Breakfast,-62.55 +Ungern (2019),SEK,Lunch,-145.95 +Ungern (2019),SEK,Dinner,-145.95 +Ungern (2020),SEK,Normalbelopp,436 +Ungern (2020),SEK,Breakfast,-65.4 +Ungern (2020),SEK,Lunch,-152.6 +Ungern (2020),SEK,Dinner,-152.6 +Uruguay (2018),SEK,Normalbelopp,503 +Uruguay (2018),SEK,Breakfast,-75.45 +Uruguay (2018),SEK,Lunch,-176.05 +Uruguay (2018),SEK,Dinner,-176.05 +Uruguay (2019),SEK,Normalbelopp,495 +Uruguay (2019),SEK,Breakfast,-74.25 +Uruguay (2019),SEK,Lunch,-173.25 +Uruguay (2019),SEK,Dinner,-173.25 +Uruguay (2020),SEK,Normalbelopp,479 +Uruguay (2020),SEK,Breakfast,-71.85 +Uruguay (2020),SEK,Lunch,-167.65 +Uruguay (2020),SEK,Dinner,-167.65 +USA (2018),SEK,Normalbelopp,689 +USA (2018),SEK,Breakfast,-103.35 +USA (2018),SEK,Lunch,-241.15 +USA (2018),SEK,Dinner,-241.15 +USA (2019),SEK,Normalbelopp,762 +USA (2019),SEK,Breakfast,-114.3 +USA (2019),SEK,Lunch,-266.7 +USA (2019),SEK,Dinner,-266.7 +USA (2020),SEK,Normalbelopp,851 +USA (2020),SEK,Breakfast,-127.65 +USA (2020),SEK,Lunch,-297.85 +USA (2020),SEK,Dinner,-297.85 +Uzbekistan (2018),SEK,Normalbelopp,230 +Uzbekistan (2018),SEK,Breakfast,-34.5 +Uzbekistan (2018),SEK,Lunch,-80.5 +Uzbekistan (2018),SEK,Dinner,-80.5 +Uzbekistan (2019),SEK,Normalbelopp,230 +Uzbekistan (2019),SEK,Breakfast,-34.5 +Uzbekistan (2019),SEK,Lunch,-80.5 +Uzbekistan (2019),SEK,Dinner,-80.5 +Uzbekistan (2020),SEK,Normalbelopp,240 +Uzbekistan (2020),SEK,Breakfast,-36 +Uzbekistan (2020),SEK,Lunch,-84 +Uzbekistan (2020),SEK,Dinner,-84 +Vanuatu (2018),SEK,Normalbelopp,587 +Vanuatu (2018),SEK,Breakfast,-88.05 +Vanuatu (2018),SEK,Lunch,-205.45 +Vanuatu (2018),SEK,Dinner,-205.45 +Vanuatu (2019),SEK,Normalbelopp,626 +Vanuatu (2019),SEK,Breakfast,-93.9 +Vanuatu (2019),SEK,Lunch,-219.1 +Vanuatu (2019),SEK,Dinner,-219.1 +Vanuatu (2020),SEK,Normalbelopp,650 +Vanuatu (2020),SEK,Breakfast,-97.5 +Vanuatu (2020),SEK,Lunch,-227.5 +Vanuatu (2020),SEK,Dinner,-227.5 +Venezuela (2020),SEK,Normalbelopp,240 +Venezuela (2020),SEK,Breakfast,-36 +Venezuela (2020),SEK,Lunch,-84 +Venezuela (2020),SEK,Dinner,-84 +Vietnam (2018),SEK,Normalbelopp,308 +Vietnam (2018),SEK,Breakfast,-46.2 +Vietnam (2018),SEK,Lunch,-107.8 +Vietnam (2018),SEK,Dinner,-107.8 +Vietnam (2019),SEK,Normalbelopp,333 +Vietnam (2019),SEK,Breakfast,-49.95 +Vietnam (2019),SEK,Lunch,-116.55 +Vietnam (2019),SEK,Dinner,-116.55 +Vietnam (2020),SEK,Normalbelopp,374 +Vietnam (2020),SEK,Breakfast,-56.1 +Vietnam (2020),SEK,Lunch,-130.9 +Vietnam (2020),SEK,Dinner,-130.9 +Vitryssland (2018),SEK,Normalbelopp,230 +Vitryssland (2018),SEK,Breakfast,-34.5 +Vitryssland (2018),SEK,Lunch,-80.5 +Vitryssland (2018),SEK,Dinner,-80.5 +Vitryssland (2019),SEK,Normalbelopp,233 +Vitryssland (2019),SEK,Breakfast,-34.95 +Vitryssland (2019),SEK,Lunch,-81.55 +Vitryssland (2019),SEK,Dinner,-81.55 +Vitryssland (2020),SEK,Normalbelopp,271 +Vitryssland (2020),SEK,Breakfast,-40.65 +Vitryssland (2020),SEK,Lunch,-94.85 +Vitryssland (2020),SEK,Dinner,-94.85 +Zambia (2018),SEK,Normalbelopp,355 +Zambia (2018),SEK,Breakfast,-53.25 +Zambia (2018),SEK,Lunch,-124.25 +Zambia (2018),SEK,Dinner,-124.25 +Zambia (2019),SEK,Normalbelopp,295 +Zambia (2019),SEK,Breakfast,-44.25 +Zambia (2019),SEK,Lunch,-103.25 +Zambia (2019),SEK,Dinner,-103.25 +Zambia (2020),SEK,Normalbelopp,260 +Zambia (2020),SEK,Breakfast,-39 +Zambia (2020),SEK,Lunch,-91 +Zambia (2020),SEK,Dinner,-91 +Zimbabwe (2018),SEK,Normalbelopp,511 +Zimbabwe (2018),SEK,Breakfast,-76.65 +Zimbabwe (2018),SEK,Lunch,-178.85 +Zimbabwe (2018),SEK,Dinner,-178.85 +Zimbabwe (2019),SEK,Normalbelopp,561 +Zimbabwe (2019),SEK,Breakfast,-84.15 +Zimbabwe (2019),SEK,Lunch,-196.35 +Zimbabwe (2019),SEK,Dinner,-196.35 +Zimbabwe (2020),SEK,Normalbelopp,487 +Zimbabwe (2020),SEK,Breakfast,-73.05 +Zimbabwe (2020),SEK,Lunch,-170.45 +Zimbabwe (2020),SEK,Dinner,-170.45 \ No newline at end of file diff --git a/docs/assets/images/Duty-of-care.png b/docs/assets/images/Duty-of-care.png index f09f8254b478..8774c0983f3f 100644 Binary files a/docs/assets/images/Duty-of-care.png and b/docs/assets/images/Duty-of-care.png differ diff --git a/docs/assets/images/ExpensifyHelp-FreeTrial-1.png b/docs/assets/images/ExpensifyHelp-FreeTrial-1.png new file mode 100644 index 000000000000..28bfcaf15847 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-FreeTrial-1.png differ diff --git a/docs/assets/images/ExpensifyHelp_CreateWorkspace_1.png b/docs/assets/images/ExpensifyHelp_CreateWorkspace_1.png index 3dcf92d028ab..e221b508a799 100644 Binary files a/docs/assets/images/ExpensifyHelp_CreateWorkspace_1.png and b/docs/assets/images/ExpensifyHelp_CreateWorkspace_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_CreateWorkspace_2.png b/docs/assets/images/ExpensifyHelp_CreateWorkspace_2.png index cafb106e897e..9953bfcbd281 100644 Binary files a/docs/assets/images/ExpensifyHelp_CreateWorkspace_2.png and b/docs/assets/images/ExpensifyHelp_CreateWorkspace_2.png differ diff --git a/docs/assets/images/ExpensifyHelp_CreateWorkspace_3.png b/docs/assets/images/ExpensifyHelp_CreateWorkspace_3.png index 08b553857110..f30ec7f9c1e3 100644 Binary files a/docs/assets/images/ExpensifyHelp_CreateWorkspace_3.png and b/docs/assets/images/ExpensifyHelp_CreateWorkspace_3.png differ diff --git a/docs/assets/images/ExpensifyHelp_InviteMembers_1.png b/docs/assets/images/ExpensifyHelp_InviteMembers_1.png index cba73c2ce150..12b000fbd07c 100644 Binary files a/docs/assets/images/ExpensifyHelp_InviteMembers_1.png and b/docs/assets/images/ExpensifyHelp_InviteMembers_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_InviteMembers_2.png b/docs/assets/images/ExpensifyHelp_InviteMembers_2.png index e09b8ac5b2b0..169013014ab5 100644 Binary files a/docs/assets/images/ExpensifyHelp_InviteMembers_2.png and b/docs/assets/images/ExpensifyHelp_InviteMembers_2.png differ diff --git a/docs/assets/images/ExpensifyHelp_InviteMembers_3.png b/docs/assets/images/ExpensifyHelp_InviteMembers_3.png index 999e6785ae5f..c8603b7a6b3c 100644 Binary files a/docs/assets/images/ExpensifyHelp_InviteMembers_3.png and b/docs/assets/images/ExpensifyHelp_InviteMembers_3.png differ diff --git a/docs/assets/images/Export-Expenses.png b/docs/assets/images/Export-Expenses.png index 37cabda7922e..8e73577bdf62 100644 Binary files a/docs/assets/images/Export-Expenses.png and b/docs/assets/images/Export-Expenses.png differ diff --git a/docs/assets/images/QBO_classic_duplicate_journal.png b/docs/assets/images/QBO_classic_duplicate_journal.png new file mode 100644 index 000000000000..8a78014b5900 Binary files /dev/null and b/docs/assets/images/QBO_classic_duplicate_journal.png differ diff --git a/docs/assets/images/QBO_classic_edit_exports.png b/docs/assets/images/QBO_classic_edit_exports.png new file mode 100644 index 000000000000..adff19e3e60a Binary files /dev/null and b/docs/assets/images/QBO_classic_edit_exports.png differ diff --git a/docs/assets/images/QBO_classic_icon.png b/docs/assets/images/QBO_classic_icon.png new file mode 100644 index 000000000000..a557b2affdf5 Binary files /dev/null and b/docs/assets/images/QBO_classic_icon.png differ diff --git a/docs/assets/images/QBO_classic_report_history.png b/docs/assets/images/QBO_classic_report_history.png new file mode 100644 index 000000000000..9a732b058c72 Binary files /dev/null and b/docs/assets/images/QBO_classic_report_history.png differ diff --git a/docs/assets/images/QBO_classic_troubleshooting_billable.png b/docs/assets/images/QBO_classic_troubleshooting_billable.png new file mode 100644 index 000000000000..876fe33dbe66 Binary files /dev/null and b/docs/assets/images/QBO_classic_troubleshooting_billable.png differ diff --git a/docs/assets/images/QBO_classic_troubleshooting_billable_2.png b/docs/assets/images/QBO_classic_troubleshooting_billable_2.png new file mode 100644 index 000000000000..5a88c48a3e5c Binary files /dev/null and b/docs/assets/images/QBO_classic_troubleshooting_billable_2.png differ diff --git a/docs/assets/images/QBO_desktop_01.png b/docs/assets/images/QBO_desktop_01.png new file mode 100644 index 000000000000..7d04236a9765 Binary files /dev/null and b/docs/assets/images/QBO_desktop_01.png differ diff --git a/docs/assets/images/QBO_desktop_02.png b/docs/assets/images/QBO_desktop_02.png new file mode 100644 index 000000000000..07bf2f006043 Binary files /dev/null and b/docs/assets/images/QBO_desktop_02.png differ diff --git a/docs/assets/images/QBO_desktop_03.png b/docs/assets/images/QBO_desktop_03.png new file mode 100644 index 000000000000..81a4176fdf52 Binary files /dev/null and b/docs/assets/images/QBO_desktop_03.png differ diff --git a/docs/assets/images/QBO_desktop_04.png b/docs/assets/images/QBO_desktop_04.png new file mode 100644 index 000000000000..d516a9e2c56a Binary files /dev/null and b/docs/assets/images/QBO_desktop_04.png differ diff --git a/docs/assets/images/QBO_desktop_05.png b/docs/assets/images/QBO_desktop_05.png new file mode 100644 index 000000000000..123adf897820 Binary files /dev/null and b/docs/assets/images/QBO_desktop_05.png differ diff --git a/docs/assets/images/QBO_desktop_06.png b/docs/assets/images/QBO_desktop_06.png new file mode 100644 index 000000000000..4e0dfbf4b574 Binary files /dev/null and b/docs/assets/images/QBO_desktop_06.png differ diff --git a/docs/assets/images/QBO_desktop_07.png b/docs/assets/images/QBO_desktop_07.png new file mode 100644 index 000000000000..519e0d3738f4 Binary files /dev/null and b/docs/assets/images/QBO_desktop_07.png differ diff --git a/docs/assets/images/QBO_desktop_08.png b/docs/assets/images/QBO_desktop_08.png new file mode 100644 index 000000000000..1573277c15c2 Binary files /dev/null and b/docs/assets/images/QBO_desktop_08.png differ diff --git a/docs/assets/images/Travel-Analytics.png b/docs/assets/images/Travel-Analytics.png index 27f696e28bcd..c4f969b6d51c 100644 Binary files a/docs/assets/images/Travel-Analytics.png and b/docs/assets/images/Travel-Analytics.png differ diff --git a/docs/assets/images/Xero_classic_Bill.png b/docs/assets/images/Xero_classic_Bill.png new file mode 100644 index 000000000000..52df4c808a59 Binary files /dev/null and b/docs/assets/images/Xero_classic_Bill.png differ diff --git a/docs/assets/images/Xero_classic_Edit_exports.png b/docs/assets/images/Xero_classic_Edit_exports.png new file mode 100644 index 000000000000..25bda4a9454a Binary files /dev/null and b/docs/assets/images/Xero_classic_Edit_exports.png differ diff --git a/docs/assets/images/Xero_classic_bank_transaction.png b/docs/assets/images/Xero_classic_bank_transaction.png new file mode 100644 index 000000000000..b730e65569a6 Binary files /dev/null and b/docs/assets/images/Xero_classic_bank_transaction.png differ diff --git a/docs/assets/images/Xero_classic_category_icon.png b/docs/assets/images/Xero_classic_category_icon.png new file mode 100644 index 000000000000..50360ecdae54 Binary files /dev/null and b/docs/assets/images/Xero_classic_category_icon.png differ diff --git a/docs/assets/images/Xero_classic_copy.png b/docs/assets/images/Xero_classic_copy.png new file mode 100644 index 000000000000..ff67fecad252 Binary files /dev/null and b/docs/assets/images/Xero_classic_copy.png differ diff --git a/docs/assets/images/Xero_classic_new_connection.png b/docs/assets/images/Xero_classic_new_connection.png new file mode 100644 index 000000000000..bb7183262e19 Binary files /dev/null and b/docs/assets/images/Xero_classic_new_connection.png differ diff --git a/docs/assets/images/Xero_classic_troubleshoot_category.png b/docs/assets/images/Xero_classic_troubleshoot_category.png new file mode 100644 index 000000000000..af6b8c2ffa0a Binary files /dev/null and b/docs/assets/images/Xero_classic_troubleshoot_category.png differ diff --git a/docs/assets/images/Xero_classic_troubleshoot_payment.png b/docs/assets/images/Xero_classic_troubleshoot_payment.png new file mode 100644 index 000000000000..441324ebf1b1 Binary files /dev/null and b/docs/assets/images/Xero_classic_troubleshoot_payment.png differ diff --git a/docs/assets/images/Xero_classic_troubleshoot_remove_redo.png b/docs/assets/images/Xero_classic_troubleshoot_remove_redo.png new file mode 100644 index 000000000000..2028457c9555 Binary files /dev/null and b/docs/assets/images/Xero_classic_troubleshoot_remove_redo.png differ diff --git a/docs/assets/images/Xero_help_01.png b/docs/assets/images/Xero_help_01.png index ce05ea83c925..ce60204866f7 100644 Binary files a/docs/assets/images/Xero_help_01.png and b/docs/assets/images/Xero_help_01.png differ diff --git a/docs/assets/images/Xero_help_02.png b/docs/assets/images/Xero_help_02.png index c2d556c7aed0..8ed2f256cf0f 100644 Binary files a/docs/assets/images/Xero_help_02.png and b/docs/assets/images/Xero_help_02.png differ diff --git a/docs/assets/images/Xero_help_03.png b/docs/assets/images/Xero_help_03.png index 30616ffd3d64..318bb274b115 100644 Binary files a/docs/assets/images/Xero_help_03.png and b/docs/assets/images/Xero_help_03.png differ diff --git a/docs/assets/images/Xero_help_04.png b/docs/assets/images/Xero_help_04.png index d0e950d3968a..b0d29bc9fde6 100644 Binary files a/docs/assets/images/Xero_help_04.png and b/docs/assets/images/Xero_help_04.png differ diff --git a/docs/assets/images/Xero_help_05.png b/docs/assets/images/Xero_help_05.png index be65e9c62960..e8265e82b652 100644 Binary files a/docs/assets/images/Xero_help_05.png and b/docs/assets/images/Xero_help_05.png differ diff --git a/docs/redirects.csv b/docs/redirects.csv index a6085d2a45e7..a1a8346b4789 100644 --- a/docs/redirects.csv +++ b/docs/redirects.csv @@ -1,4 +1,5 @@ sourceURL,targetURL +https://community.expensify.com,https://help.expensify.com https://community.expensify.com/discussion/5634/deep-dive-how-long-will-it-take-for-me-to-receive-my-reimbursement,https://help.expensify.com/articles/expensify-classic/expenses/reports/Reimbursements https://community.expensify.com/discussion/4925/how-to-dispute-an-expensify-card-transaction,https://help.expensify.com/articles/expensify-classic/expensify-card/Dispute-A-Transaction https://community.expensify.com/discussion/5184/faq-how-am-i-protected-from-fraud-using-the-expensify-card,https://help.expensify.com/articles/expensify-classic/expensify-card/Dispute-A-Transaction @@ -24,8 +25,7 @@ https://community.expensify.com/discussion/5655/deep-dive-what-is-a-vacation-del https://community.expensify.com/discussion/5194/how-to-assign-a-vacation-delegate-for-an-employee-through-domains,https://help.expensify.com/articles/expensify-classic/copilots-and-delegates/Vacation-Delegate https://community.expensify.com/discussion/5190/how-to-individually-assign-a-vacation-delegate-from-account-settings,https://help.expensify.com/articles/expensify-classic/copilots-and-delegates/Vacation-Delegate https://community.expensify.com/discussion/5274/how-to-set-up-an-adp-indirect-integration-with-expensify,https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/ADP -https://community.expensify.com/discussion/5776/how-to-create-mileage-expenses-in-expensify,https://help.expensify.com/articles/expensify-classic/expenses/Distance-Tracking -https://community.expensify.com/discussion/7385/how-to-enable-two-factor-authentication-in-your-account,https://help.expensify.com/expensify-classic/hubs/settings/account-settings +https://community.expensify.com/discussion/5776/how-to-create-mileage-expenses-in-expensify,https://help.expensify.com/articles/expensify-classic/workspaces/Expense-Settings#distance-expenses https://community.expensify.com/discussion/5149/how-to-manage-your-devices-in-expensify,https://help.expensify.com/expensify-classic/hubs/settings/account-settings https://community.expensify.com/discussion/4432/how-to-add-a-secondary-login,https://help.expensify.com/expensify-classic/hubs/settings/account-settings https://community.expensify.com/discussion/6794/how-to-change-your-email-in-expensify,https://help.expensify.com/expensify-classic/hubs/settings/account-settings @@ -38,18 +38,18 @@ https://community.expensify.com/discussion/1460/schedule-a-demo,https://help.exp https://community.expensify.com/discussion/835/what-is-the-difference-between-a-category-and-a-tag,https://help.expensify.com/expensify-classic/hubs/getting-started https://community.expensify.com/discussion/7703/getting-started-video,https://help.expensify.com/expensify-classic/hubs/getting-started https://community.expensify.com/discussion/1845/how-to-set-up-account-and-add-users,https://help.expensify.com/expensify-classic/hubs/getting-started -https://community.expensify.com/discussion/8629/employee-training-e-learning-program,https://help.expensify.com/expensify-classic/hubs/getting-started +https://community.expensify.com/discussion/8629/employee-training-e-learning-program,https://help.expensify.com/articles/expensify-classic/getting-started/Join-your-company's-workspace https://community.expensify.com/discussion/1607/on-demand-webinars,https://help.expensify.com/expensify-classic/hubs/getting-started https://community.expensify.com/discussion/5444/admin-onboarding-webinar-faqs,https://help.expensify.com/expensify-classic/hubs/getting-started https://community.expensify.com/discussion/5417/employee-training-webinar-faqs,https://help.expensify.com/expensify-classic/hubs/getting-started https://community.expensify.com/discussion/5885/overview-the-employee-training-webinar,https://help.expensify.com/expensify-classic/hubs/getting-started https://community.expensify.com/discussion/5854/overview-the-expensify-admin-onboarding-webinar,https://help.expensify.com/expensify-classic/hubs/getting-started https://community.expensify.com/discussion/4699/how-to-download-the-mobile-app,https://help.expensify.com/expensify-classic/hubs/getting-started -https://community.expensify.com/discussion/4524/how-to-set-up-the-uber-integration,https://help.expensify.com/expensify-classic/hubs/getting-started -https://community.expensify.com/discussion/5212/how-to-connect-your-policy-to-netsuite-token-based-authentication,https://help.expensify.com/expensify-classic/hubs/getting-started +https://community.expensify.com/discussion/4524/how-to-set-up-the-uber-integration,https://help.expensify.com/articles/expensify-classic/connections/Uber +https://community.expensify.com/discussion/5212/how-to-connect-your-policy-to-netsuite-token-based-authentication,https://help.expensify.com/articles/expensify-classic/connections/netsuite/Connect-To-NetSuite https://community.expensify.com/discussion/5124/how-to-add-your-name-and-photo-to-your-account,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Add-profile-photo -https://community.expensify.com/discussion/5922/deep-dive-day-1-with-expensify-for-submitters,https://help.expensify.com/expensify-classic/hubs/getting-started -https://community.expensify.com/discussion/5934/day-1-with-expensify-admins-and-accountants,https://help.expensify.com/expensify-classic/hubs/getting-started +https://community.expensify.com/discussion/5922/deep-dive-day-1-with-expensify-for-submitters,https://help.expensify.com/articles/expensify-classic/getting-started/Join-your-company's-workspace +https://community.expensify.com/discussion/5934/day-1-with-expensify-admins-and-accountants,https://help.expensify.com/articles/expensify-classic/getting-started/Create-a-company-workspace https://community.expensify.com/discussion/5694/deep-dive-admin-training-and-setup-resources,https://help.expensify.com/expensify-classic/hubs/getting-started https://help.expensify.com/articles/expensify-classic/expensify-card/Expensify-Card-Perks.html,https://use.expensify.com/company-credit-card https://help.expensify.com/articles/expensify-classic/expensify-partner-program/How-to-Join-the-ExpensifyApproved!-Partner-Program.html,https://use.expensify.com/accountants-program @@ -62,12 +62,10 @@ https://community.expensify.com/discussion/7318/deep-dive-company-credit-card-im https://community.expensify.com/discussion/2673/personalize-your-commercial-card-feed-name,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds https://community.expensify.com/discussion/6569/how-to-import-and-assign-company-cards-from-csv-file,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import https://community.expensify.com/discussion/4714/how-to-set-up-a-direct-bank-connection-for-company-cards,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections -https://community.expensify.com/discussion/4828/how-to-reconcile-your-company-cards-statement-in-expensify,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation https://community.expensify.com/discussion/5366/deep-dive-troubleshooting-credit-card-issues-in-expensify,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting https://community.expensify.com/discussion/9554/how-to-set-up-global-reimbursemen,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursements https://community.expensify.com/discussion/4463/how-to-remove-or-manage-settings-for-imported-personal-cards,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards -https://community.expensify.com/discussion/5793/how-to-connect-your-personal-card-to-import-expenses,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards -https://community.expensify.com/discussion/4826/how-to-set-your-annual-subscription-size,https://use.expensify.com/ +https://community.expensify.com/discussion/5793/how-to-connect-your-personal-card-to-import-expenses,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/Personal-Credit-Cards https://community.expensify.com/discussion/5667/deep-dive-how-does-the-annual-subscription-billing-work,https://use.expensify.com/ https://help.expensify.com/articles/expensify-classic/getting-started/approved-accountants/Your-Expensify-Partner-Manager,https://help.expensify.com/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager https://help.expensify.com/expensify-classic/hubs/getting-started/plan-types,https://use.expensify.com/ @@ -370,3 +368,161 @@ https://community.expensify.com/discussion/5665/deep-dive-troubleshooting-expens https://community.expensify.com/discussion/3998/expensify-grab-smoother-business-travel-in-southeast-asia,https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations https://community.expensify.com/discussion/5125/faq-why-is-uber-creating-an-expensify-account-for-me,https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Uber https://community.expensify.com/discussion/4051/deep-dive-taking-over-as-an-expensify-admin-here-s-your-guide-to-a-smooth-transition,https://help.expensify.com/articles/expensify-classic/workspaces/Admin-offboarding-checklist +https://community.expensify.com/discussion/6569/how-to-import-and-assign-company-cards-from-spreadsheet-or-ofx-file/p1,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/CSV-Import +https://community.expensify.com/discussion/4476/how-to-enable-scheduled-submit-for-a-group-policy,https://help.expensify.com/articles/expensify-classic/reports/Automatically-submit-employee-reports +https://community.expensify.com/discussion/6018/deep-dive-day-1-with-the-expensify-card,https://help.expensify.com/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features +https://community.expensify.com/discussion/5836/how-to-email-receipts-to-expensify,https://help.expensify.com/articles/expensify-classic/expenses/Add-an-expense#email-a-receipt +https://community.expensify.com/discussion/7500/how-to-pay-your-company-bills-in-expensify/,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Reimburse-Reports-Invoices-and-Bills +https://community.expensify.com/discussion/7385/how-to-enable-two-factor-authentication-in-your-account,https://help.expensify.com/articles/expensify-classic/settings/Enable-two-factor-authentication +https://community.expensify.com/discussion/4432/how-to-add-a-secondary-login/,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Change-or-add-email-address +https://community.expensify.com/discussion/5539/deep-dive-what-is-a-copilot-what-are-the-different-types/,https://help.expensify.com/articles/expensify-classic/copilots-and-delegates/Assign-or-remove-a-Copilot +https://help.expensify.com/articles/expensify-classic/copilots-and-delegates/Vacation-Delegate,https://help.expensify.com/articles/expensify-classic/copilots-and-delegates/Delegate-when-out-of-office +https://community.expensify.com/discussion/5678/deep-dive-secondary-login-merge-accounts-what-does-this-mean,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Merge-accounts +https://community.expensify.com/discussion/5103/how-to-create-and-use-custom-units/,https://help.expensify.com/ +https://community.expensify.com/discussion/6530/how-to-set-your-time-zone-for-report-history-comments,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Set-time-zone +https://community.expensify.com/discussion/5651/deep-dive--practices-when-youre-running-into-trouble-receiving-emails-from-expensify,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Set-Notifications +https://community.expensify.com/discussion/5793/how-to-connect-your-personal-card-to-import-expenses/,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/Personal-Credit-Cards +https://community.expensify.com/discussion/5677/deep-dive-security-how-expensify-protects-your-information,https://help.expensify.com/articles/new-expensify/settings/Encryption-and-Data-Security +https://community.expensify.com/discussion/4641/how-to-add-a-u-s-deposit-account,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-Personal-US-Bank-Account +https://community.expensify.com/discussion/4751/how-to-how-to-add-an-ach-withdrawal-account-us-only/,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account +https://community.expensify.com/discussion/7428/how-to-pay-get-paid-for-invoices-using-paypal-me-and-expensify,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Third-Party-Payments +https://community.expensify.com/discussion/7252/deep-dive-best-practices-for-creating-and-sending-invoices,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Third-Party-Payments +https://community.expensify.com/discussion/4482/how-to-update-payment-details,https://help.expensify.com/articles/expensify-classic/workspaces/Assign-billing-owner-and-payment-account +https://community.expensify.com/discussion/5934/day-1-with-expensify-admins-and-accountants/,https://help.expensify.com/articles/expensify-classic/getting-started/Create-a-company-workspace +https://community.expensify.com/discussion/5542/deep-dive-what-are-ereceipts/,https://help.expensify.com/articles/expensify-classic/workspaces/Expense-Settings#ereceipts +https://community.expensify.com/discussion/5776/how-to-create-mileage-expenses-in-expensify/,https://help.expensify.com/articles/expensify-classic/workspaces/Expense-Settings#distance-expenses +https://community.expensify.com/discussion/4740/how-to-create-a-time-expense,https://help.expensify.com/articles/expensify-classic/workspaces/Expense-Settings#time-expenses +https://community.expensify.com/discussion/5743/deep-dive-currency-in-expensify-overview/,https://help.expensify.com/articles/expensify-classic/workspaces/Set-Currency +https://community.expensify.com/discussion/4976/,https://help.expensify.com/articles/expensify-classic/reports/Automatically-submit-employee-reports +https://community.expensify.com/discussion/4831/how-to-set-up-default-report-titles,https://help.expensify.com/articles/expensify-classic/reports/Set-default-report-title +https://community.expensify.com/discussion/4485/how-to-set-up-and-use-report-fields,https://help.expensify.com/articles/expensify-classic/reports/Add-custom-fields-to-reports-and-invoices +https://community.expensify.com/discussion/5212/how-to-connect-your-policy-to-netsuite-token-based-authentication/,https://help.expensify.com/articles/expensify-classic/connections/netsuite/Connect-To-NetSuite +https://community.expensify.com/discussion/4833/how-to-connect-your-policy-to-quickbooks-online/,https://help.expensify.com/articles/expensify-classic/connections/quickbooks-online/Connect-To-QuickBooks-Online +https://community.expensify.com/discussion/5715/how-to-connect-to-quickbooks-desktop,https://help.expensify.com/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop +https://community.expensify.com/discussion/5282/how-to-connect-your-policy-to-xero/,https://help.expensify.com/articles/expensify-classic/connections/xero/Connect-To-Xero +https://community.expensify.com/discussion/6487/how-to-connect-to-sage-intacct,https://help.expensify.com/articles/expensify-classic/connections/sage-intacct/Connect-To-Sage-Intacct +https://community.expensify.com/discussion/5241/how-to-connect-financialforce-psa-srp-to-your-policy/,https://help.expensify.com/articles/expensify-classic/connections/certinia/Connect-To-Certinia +https://community.expensify.com/discussion/5536/deep-dive-what-is-a-secondary-login-and-when-you-d-use-it/,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Change-or-add-email-address +https://community.expensify.com/discussion/5732/deep-dive-all-about-policy-categories/,https://help.expensify.com/articles/expensify-classic/workspaces/Create-categories +https://community.expensify.com/discussion/5469/deep-dive-auto-categorize-card-expenses-with-default-categories,https://help.expensify.com/articles/expensify-classic/workspaces/Set-up-category-automation +https://community.expensify.com/discussion/4708/how-to-set-up-and-add-single-tags,https://help.expensify.com/articles/expensify-classic/workspaces/Create-tags +https://community.expensify.com/discussion/5756/how-to-set-up-and-manage-multi-level-tagging/,https://help.expensify.com/articles/expensify-classic/workspaces/Create-tags#multi-level-tags +https://community.expensify.com/discussion/5044/how-to-set-up-multiple-taxes-on-indirect-connections,https://help.expensify.com/articles/expensify-classic/workspaces/Tax-Tracking +https://community.expensify.com/discussion/4643/how-to-invite-people-to-your-policy-using-a-join-link/,https://help.expensify.com/articles/expensify-classic/workspaces/Invite-members-and-assign-roles#invite-with-a-link +https://community.expensify.com/discussion/5700/deep-dive-approval-workflow-overview,https://help.expensify.com/articles/expensify-classic/reports/Create-a-report-approval-workflow +https://community.expensify.com/discussion/4804/how-to-set-up-concierge-report-approval,https://help.expensify.com/articles/expensify-classic/reports/Require-review-for-over-limit-expenses +https://community.expensify.com/discussion/4975/how-to-invite-users-to-your-policy-manually-or-in-bulk/,https://help.expensify.com/articles/expensify-classic/workspaces/Invite-members-and-assign-roles#invite-with-a-link +https://community.expensify.com/discussion/4743/how-to-enforce-your-group-policys-approval-work-flow,https://help.expensify.com/articles/expensify-classic/reports/Create-a-report-approval-workflow#enforce-workflow +https://community.expensify.com/discussion/4781/how-to-add-an-australian-withdrawal-account-details,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Enable-Australian-Reimbursements +https://community.expensify.com/discussion/4772/how-to-add-a-single-rate-per-diem,https://help.expensify.com/articles/expensify-classic/workspaces/Enable-per-diem-expenses +https://community.expensify.com/discussion/4825/how-to-create-and-send-invoices-web-mobile/,https://help.expensify.com/articles/expensify-classic/workspaces/Set-Up-Invoicing +https://community.expensify.com/discussion/8850/how-to-enable-monthly-settlement,https://help.expensify.com/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features#change-the-settlement-frequency +https://community.expensify.com/discussion/4828/how-to-match-your-company-cards-statement-to-expensify/,https://help.expensify.com/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features#reconciling-expenses-and-settlements +https://community.expensify.com/discussion/5751/deep-dive-domain-groups-and-permissions-what-are-they-all-about,https://help.expensify.com/articles/expensify-classic/domains/Create-A-Group +https://community.expensify.com/categories/expensify-org-general-questions-and-discussions,https://www.expensify.org/ +https://community.expensify.com/discussion/4832/how-to-enable-saml-sso,https://help.expensify.com/articles/expensify-classic/domains/SAML-SSO +https://community.expensify.com/discussion/4476/how-to-enable-scheduled-submit-for-a-group-policy/,https://help.expensify.com/articles/expensify-classic/reports/Automatically-submit-employee-reports +https://community.expensify.com/discussion/4524/how-to-set-up-the-uber-integration/,https://help.expensify.com/articles/expensify-classic/connections/Uber +https://community.expensify.com/discussion/4828/how-to-match-your-company-cards-statement-to-expensify/p1,https://help.expensify.com/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features#reconciling-expenses-and-settlements +https://community.expensify.com/discussion/4842/how-to-split-expenses-on-the-web-and-mobile-app,https://help.expensify.com/articles/expensify-classic/expenses/Split-an-expense +https://community.expensify.com/discussion/4948/faq-why-didnt-my-ereceipt-generate/,https://help.expensify.com/articles/expensify-classic/workspaces/Expense-Settings#ereceipts +https://community.expensify.com/discussion/5145/how-to-connect-to-sage-intacct-role-based-permissions-expense-reports/,https://help.expensify.com/articles/expensify-classic/connections/sage-intacct/Connect-To-Sage-Intacct +https://community.expensify.com/discussion/5366/troubleshooting-credit-card-issues-in-expensify/,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Troubleshooting +https://community.expensify.com/discussion/5541/deep-dive-what-is-smartscan-and-how-it-works/,https://help.expensify.com/articles/expensify-classic/expenses/Add-an-expense#smartscan-a-receipt +https://community.expensify.com/discussion/5678/deep-dive-secondary-login-merge-accounts-what-does-this-mean/p1,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Merge-accounts +https://community.expensify.com/discussion/5922/deep-dive-day-1-with-expensify-for-submitters/p1,https://help.expensify.com/articles/expensify-classic/getting-started/Join-your-company's-workspace +https://community.expensify.com/discussion/8629/employee-training-e-learning-programme/p1,https://help.expensify.com/articles/expensify-classic/getting-started/Join-your-company's-workspace +https://community.expensify.com/discussion/5124/how-to-add-your-name-and-photo-to-your-account/,https://help.expensify.com/expensify-classic/hubs/settings/account-settings +https://community.expensify.com/post/discussion/3rd-party-integrations,https://help.expensify.com/expensify-classic/hubs/connections/ +https://community.expensify.com/post/discussion/advanced-admin-controls,https://help.expensify.com/expensify-classic/hubs/workspaces/ +https://community.expensify.com/post/discussion/becoming-an-expensifyapproved!-accountant,https://help.expensify.com/expensify-classic/hubs/expensify-partner-program/ +https://help.expensify.com/articles/expensify-classic/workspaces/Invoicing.html,https://help.expensify.com/articles/expensify-classic/workspaces/Set-Up-Invoicing +https://community.expensify.com/discussion/4288/netsuite-expensierror-ns0092-you-do-not-have-permission-to-set-a-value-for-expense-isbillable,https://help.expensify.com/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting +https://community.expensify.com/discussion/4461/how-to-set-up-lyft-for-individual-use,https://help.expensify.com/articles/expensify-classic/connections/Lyft +https://community.expensify.com/discussion/4520/how-to-close-your-account,https://help.expensify.com/articles/new-expensify/settings/Close-account +https://community.expensify.com/discussion/4520/how-to-delete-your-account,https://help.expensify.com/articles/new-expensify/settings/Close-account +https://community.expensify.com/discussion/4525/how-to-resend-an-invite,https://help.expensify.com/articles/expensify-classic/workspaces/Invite-members-and-assign-roles +https://community.expensify.com/discussion/4638/how-to-enable-category-specific-rules-and-descriptions,https://help.expensify.com/articles/expensify-classic/workspaces/Enable-and-set-up-expense-violations +https://community.expensify.com/discussion/4644/how-to-claim-and-validate-your-domain-in-expensify,https://help.expensify.com/articles/expensify-classic/domains/Claim-And-Verify-A-Domain +https://community.expensify.com/discussion/4704/how-to-set-mileage-rates-and-track-tax-on-distance-expenses,https://help.expensify.com/articles/expensify-classic/workspaces/Expense-Settings +https://community.expensify.com/discussion/4774/how-to-enable-google-apps-sso-with-your-expensify-group-policy,https://help.expensify.com/articles/expensify-classic/domains/SAML-SSO +https://community.expensify.com/discussion/4780/how-to-export-to-individual-gl-accounts,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Company-Card-Settings +https://community.expensify.com/discussion/4819/how-to-set-up-a-visa-commercial-feed,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Commercial-Card-Feeds +https://community.expensify.com/discussion/4820/how-to-set-up-a-mastercard-commercial-feed,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Commercial-Card-Feeds +https://community.expensify.com/discussion/4822/how-to-set-up-an-american-express-commercial-feed,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Commercial-Card-Feeds +https://community.expensify.com/discussion/4822/how-to-set-up-an-american-express-commercial-feed%23latest,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Commercial-Card-Feeds +https://community.expensify.com/discussion/4826/how-to-set-your-annual-subscription-size,https://help.expensify.com/articles/expensify-classic/expensify-billing/Billing-Overview#annual-subscription +https://community.expensify.com/discussion/4841/how-to-change-the-billing-owner-for-your-policy,https://help.expensify.com/articles/expensify-classic/workspaces/Assign-billing-owner-and-payment-account +https://community.expensify.com/discussion/4848/deep-dive-expensify-card-and-quickbooks-online-auto-reconciliation-how-it-works,https://help.expensify.com/articles/expensify-classic/expensify-card/Expensify-Card-Reconciliation +https://community.expensify.com/discussion/4851/deep-dive-what-are-smart-limits,https://help.expensify.com/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features#smart-limits +https://community.expensify.com/discussion/4851/deep-dive-what-are-unapproved-expense-limits,https://help.expensify.com/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features#smart-limits +https://community.expensify.com/discussion/4853/how-to-set-or-edit-the-default-unapproved-expense-limit-for-a-group,https://help.expensify.com/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features#smart-limits +https://community.expensify.com/discussion/4854/how-to-set-or-edit-the-default-unapproved-expense-limit-for-an-individual-cardholder,https://help.expensify.com/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features#smart-limits +https://community.expensify.com/discussion/4874/how-to-apply-for-the-expensify-card,https://help.expensify.com/articles/expensify-classic/expensify-card/Request-the-Card +https://community.expensify.com/discussion/4875/how-to-connect-your-business-bank-account,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Connect-a-Business-Bank-Account +https://community.expensify.com/discussion/4931/how-to-cancel-your-expensify-card,https://help.expensify.com/articles/expensify-classic/expensify-card/Deactivate-or-cancel-an-Expensify-Card +https://community.expensify.com/discussion/4977/how-to-enable-tax-tracking,https://help.expensify.com/articles/expensify-classic/workspaces/Tax-Tracking +https://community.expensify.com/discussion/4978/how-to-reimburse-a-report-via-ach,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Reimburse-Reports-Invoices-and-Bills +https://community.expensify.com/discussion/5067/faq-expensierror-xro068-organization-is-not-subscribed-to-currency-x,https://help.expensify.com/articles/expensify-classic/connections/xero/Xero-Troubleshooting +https://community.expensify.com/discussion/5068/faq-expensierror-xro076-this-report-has-already-been-exported-once-to-xero,https://help.expensify.com/articles/expensify-classic/connections/xero/Xero-Troubleshooting +https://community.expensify.com/discussion/5143/faq-expensierror-ns0023-employee-does-not-exist-in-netsuite,https://help.expensify.com/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting +https://community.expensify.com/discussion/5144/faq-expensierror-ns0024-invalid-customer-tag,https://help.expensify.com/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting +https://community.expensify.com/discussion/5209/deep-dive-the-expensify-card,https://help.expensify.com/expensify-classic/hubs/expensify-card/ +https://community.expensify.com/discussion/5222/faq-why-am-i-getting-an-invalid-credentials-login-failed-error-message-when-importing-my-card,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Troubleshooting +https://community.expensify.com/discussion/5231/faq-expensierror-xro027-expense-s-on-the-report-is-categorized-with-a-category-no-longer-in-xero,https://help.expensify.com/articles/expensify-classic/connections/xero/Xero-Troubleshooting +https://community.expensify.com/discussion/5242/faq-netsuite-you-do-not-have-permissions-to-set-a-value-for-element-recipturl,https://help.expensify.com/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting +https://community.expensify.com/discussion/5251/faq-netsuite-you-do-not-have-permissions-to-set-a-value-for-element,https://help.expensify.com/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting +https://community.expensify.com/discussion/5271/how-to-set-up-an-indirect-accounting-integration,https://help.expensify.com/articles/expensify-classic/connections/Indirect-Accounting-Integrations +https://community.expensify.com/discussion/5321/how-to-set-up-saml-authentication-with-adfs-in-expensify,https://help.expensify.com/articles/expensify-classic/domains/SAML-SSO +https://community.expensify.com/discussion/5499/deep-dive-configure-coding-for-sage-intacct,https://help.expensify.com/articles/expensify-classic/connections/sage-intacct/Configure-Sage-Intacct +https://community.expensify.com/discussion/5580/deep-dive-configure-advanced-settings-for-netsuite,https://help.expensify.com/articles/new-expensify/connections/netsuite/Connect-to-NetSuite#step-3-configure-advanced-settings +https://community.expensify.com/discussion/5632/deep-dive-configure-coding-for-netsuite,https://help.expensify.com/articles/new-expensify/connections/netsuite/Connect-to-NetSuite#configure-netsuite-integration +https://community.expensify.com/discussion/5649/deep-dive-configure-advanced-settings-for-quickbooks-online,https://help.expensify.com/articles/expensify-classic/connections/quickbooks-online/Configure-Quickbooks-Online +https://community.expensify.com/discussion/5654/deep-dive-using-expense-rules-to-vendor-match-when-exporting-to-an-accounting-package,https://help.expensify.com/articles/expensify-classic/expenses/Expense-Rules#how-can-i-use-expense-rules-to-vendor-match-when-exporting-to-an-accounting-package +https://community.expensify.com/discussion/5656/deep-dive-configure-coding-for-xero/,https://help.expensify.com/articles/new-expensify/connections/xero/Connect-to-Xero#step-2-configure-import-settings +https://community.expensify.com/discussion/5698/deep-dive-financialforce-ffa-coding-configurations/,https://help.expensify.com/articles/expensify-classic/connections/certinia/Connect-To-Certinia +https://community.expensify.com/discussion/5742/deep-dive-what-is-scheduled-submit-and-how-does-it-work,https://help.expensify.com/articles/expensify-classic/reports/Automatically-submit-employee-reports +https://community.expensify.com/discussion/5752/how-to-use-the-comments-section-of-a-report,https://help.expensify.com/articles/expensify-classic/reports/Add-comments-and-attachments-to-a-report +https://community.expensify.com/discussion/5781/how-to-cancel-your-expensify-card,https://help.expensify.com/articles/expensify-classic/expensify-card/Deactivate-or-cancel-an-Expensify-Card +https://community.expensify.com/discussion/5799/deep-dive-date-formating-for-formulas,https://help.expensify.com/articles/expensify-classic/spending-insights/Custom-Templates +https://community.expensify.com/discussion/5864/how-to-add-a-personal-bank-account-to-receive-reimbursement,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-Personal-US-Bank-Account +https://community.expensify.com/discussion/5941/how-to-reimburse-overseas-employees-for-us-employers/,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Enable-Global-Reimbursements +https://community.expensify.com/discussion/6203/deep-dive-expensify-card-and-netsuite-auto-reconciliation-how-it-works,https://help.expensify.com/articles/expensify-classic/expensify-card/Expensify-Card-Reconciliation +https://community.expensify.com/discussion/6698/faq-troubleshooting-bank-and-card-errors,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Troubleshooting +https://community.expensify.com/discussion/6827/what-s-happening-to-my-expensify-bill,https://help.expensify.com/articles/expensify-classic/expensify-billing/Billing-Overview +https://community.expensify.com/discussion/6898/deep-dive-guide-to-billing,https://help.expensify.com/articles/expensify-classic/expensify-billing/Billing-Overview +https://community.expensify.com/discussion/7231/how-to-export-invoices-to-netsuite,https://help.expensify.com/articles/new-expensify/connections/netsuite/Connect-to-NetSuite#export-invoices-to +https://community.expensify.com/discussion/7335/faq-what-is-the-expensify-card-auto-reconciliation-process,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Send-an-invoice +https://community.expensify.com/discussion/7524/how-to-set-up-disable-2fa-for-your-domain,https://help.expensify.com/articles/expensify-classic/domains/Add-Domain-Members-and-Admins +https://community.expensify.com/discussion/7736/faq-troubleshooting-two-factor-authentication-issues,https://help.expensify.com/articles/expensify-classic/settings/Enable-two-factor-authentication +https://community.expensify.com/discussion/7862/introducing-expensify-cash-open-source-financial-group-chat-built-with-react-native,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Reimburse-Reports-Invoices-and-Bills +https://community.expensify.com/discussion/7931/how-to-become-an-expensify-org-donor,https://www.expensify.org/donate +https://community.expensify.com/discussion/8705/how-to-change-an-invoice-to-an-expense-report/,https://help.expensify.com/articles/expensify-classic/reports/Edit-a-report +https://community.expensify.com/discussion/8803/settle-your-expensify-cards-monthly-or-daily-you-pick,https://help.expensify.com/articles/expensify-classic/expensify-card/Statements#expensify-card-settlement-frequency +https://community.expensify.com/discussion/4784/how-to-alternate-option-submit-as-part-of-approval-workflow,https://help.expensify.com/articles/expensify-classic/reports/Create-a-report-approval-workflow +https://community.expensify.com/discussion/4863/how-to-assign-and-unassign-company-cards,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Commercial-Card-Feeds#how-to-assign-company-cards +https://community.expensify.com/discussion/4902/how-to-expense-grab-airport-mobile-orders-with-expensify,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations#how-to-connect-to-grab +https://community.expensify.com/discussion/4953/how-to-forward-hoteltonight-expenses-to-your-expensify-account,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations#how-to-connect-to-hoteltonight +https://community.expensify.com/discussion/5042/faq-expensierror-xro052-expenses-are-not-categorized-with-a-xero-account,https://help.expensify.com/articles/expensify-classic/connections/xero/Xero-Troubleshooting +https://community.expensify.com/discussion/5151/how-to-connect-spothero-to-your-expensify-account-using-a-business-profile,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations#how-to-connect-to-spothero +https://community.expensify.com/discussion/5154/how-to-connect-tripactions-to-your-expensify-group-policy,https://help.expensify.com/articles/expensify-classic/connections/Navan +https://community.expensify.com/discussion/5156/how-to-connect-grab-to-your-expensify-account-using-a-business-profile,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations#how-to-connect-to-grab +https://community.expensify.com/discussion/5159/faq-what-does-please-update-your-expensify-bundle-mean-financialforce-psa-srp,https://help.expensify.com/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting +https://community.expensify.com/discussion/5554/deep-dive-what-are-domains-and-how-do-i-use-them,https://help.expensify.com/expensify-classic/hubs/domains/ +https://community.expensify.com/discussion/5587/deep-dive-understanding-policy-types-and-billing-options,https://help.expensify.com/articles/expensify-classic/expensify-billing/Change-Plan-Or-Subscription +https://community.expensify.com/discussion/5643/deep-dive-submit-and-approve,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Approve-and-pay-expenses +https://community.expensify.com/discussion/5668/deep-dive-how-trips-work-and-benefits,https://help.expensify.com/articles/expensify-classic/expenses/Trips +https://community.expensify.com/discussion/5689/deep-dive-is-a-direct-connection-the-best-option/,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Direct-Bank-Connections +https://community.expensify.com/discussion/6592/deep-dive-ach-reimbursement-timing,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments#faq +https://community.expensify.com/discussion/7914/how-to-pay-an-invoice-and-bill-in-expensify,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Reimburse-Reports-Invoices-and-Bills +https://community.expensify.com/discussion/8229/connecting-kayak-for-business,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations#how-to-connect-to-kayak-for-business +https://community.expensify.com/discussion/9507/how-to-use-the-delta-receipt-integration,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations +https://community.expensify.com/discussion/8814/a-welcome-update-to-expensifyapproved-billing,https://help.expensify.com/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide +https://community.expensify.com/discussion/4480/how-to-connect-to-bill-com,https://integrations.expensify.com/Integration-Server/doc/#report-exporter +https://community.expensify.com/discussion/5509/deep-dive-who-can-reimburse-reports-and-what-happens-when-you-do,https://help.expensify.com/articles/expensify-classic/workspaces/Configure-Reimbursement-Settings +https://community.expensify.com/discussion/4952/how-to-connect-pana-to-your-expensify-account,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations +https://community.expensify.com/discussion/4939/how-to-connect-upside-to-your-expensify-account,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations +https://community.expensify.com/discussion/4905/how-to-setup-the-parking-spot-to-automatically-forward-airport-parking-receipts-to-expensify,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations +https://community.expensify.com/discussion/5324/how-to-connect-parkwhiz-to-your-expensify-account-using-a-business-profile,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations +https://community.expensify.com/discussion/6983/faq-why-do-i-need-to-provide-personal-documentation-when-setting-up-updating-my-bank-account,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Connect-a-Business-Bank-Account#faq +https://community.expensify.com/discussion/6191/list-of-restricted-businesses,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account#are-there-certain-industries-or-businesses-for-which-expensify-cannot-process-payments diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index ac9c1b318aad..bd301e478ada 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -1015,11 +1015,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -1822,11 +1818,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -1894,11 +1886,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = ""; PRODUCT_NAME = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; @@ -1976,11 +1964,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -2125,11 +2109,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -2266,11 +2246,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = ""; PRODUCT_NAME = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; @@ -2405,11 +2381,7 @@ "$(inherited)", "-DRN_FABRIC_ENABLED", ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = ""; PRODUCT_NAME = ""; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index b3a82694cc5a..d601d4a5eb05 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 9.0.20 + 9.0.24 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.20.4 + 9.0.24.0 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 52c1db1df541..2faff3e32557 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 9.0.20 + 9.0.24 CFBundleSignature ???? CFBundleVersion - 9.0.20.4 + 9.0.24.0 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 15bf27aa9b2e..fce2a5696573 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 9.0.20 + 9.0.24 CFBundleVersion - 9.0.20.4 + 9.0.24.0 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f5c825e63868..1a1a21aba7a3 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1343,7 +1343,27 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-pager-view (6.2.3): + - react-native-pager-view (6.3.4): + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - react-native-pager-view/common (= 6.3.4) + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-pager-view/common (6.3.4): - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -1871,7 +1891,7 @@ PODS: - RNGoogleSignin (10.0.1): - GoogleSignIn (~> 7.0) - React-Core - - RNLiveMarkdown (0.1.111): + - RNLiveMarkdown (0.1.117): - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -1889,9 +1909,9 @@ PODS: - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNLiveMarkdown/common (= 0.1.111) + - RNLiveMarkdown/common (= 0.1.117) - Yoga - - RNLiveMarkdown/common (0.1.111): + - RNLiveMarkdown/common (0.1.117): - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -2568,7 +2588,7 @@ SPEC CHECKSUMS: react-native-keyboard-controller: 47c01b0741ae5fc84e53cf282e61cfa5c2edb19b react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d react-native-netinfo: 02d31de0e08ab043d48f2a1a8baade109d7b6ca5 - react-native-pager-view: ccd4bbf9fc7effaf8f91f8dae43389844d9ef9fa + react-native-pager-view: 770eee116657fca3d30329b2e8aa5a282a9dc722 react-native-pdf: 762369633665ec02ac227aefe2f4558b92475c23 react-native-performance: fb21ff0c9bd7a10789c69d948f25b0067d29f7a9 react-native-plaid-link-sdk: ba40d1b13cca4b946974fafd9ae278e0fb697d87 @@ -2614,7 +2634,7 @@ SPEC CHECKSUMS: RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 RNGestureHandler: 74b7b3d06d667ba0bbf41da7718f2607ae0dfe8f RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0 - RNLiveMarkdown: cf2707e6050a3548bde4f66bd752d721f91e8ab6 + RNLiveMarkdown: 54e6a7dfd3e92fdb1d2dab1b64ee8a56d56acd91 RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 rnmapbox-maps: df8fe93dbd251f25022f4023d31bc04160d4d65c RNPermissions: d2392b754e67bc14491f5b12588bef2864e783f3 diff --git a/package-lock.json b/package-lock.json index 186633837bfc..e1ce1dde84dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "new.expensify", - "version": "9.0.20-4", + "version": "9.0.24-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.20-4", + "version": "9.0.24-0", "hasInstallScript": true, "license": "MIT", "dependencies": { "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "^0.1.111", + "@expensify/react-native-live-markdown": "0.1.117", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-listformat": "^7.2.2", @@ -55,7 +55,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "2.0.64", + "expensify-common": "2.0.72", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.11.0", @@ -103,13 +103,13 @@ "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", "react-native-onyx": "2.0.64", - "react-native-pager-view": "6.2.3", + "react-native-pager-view": "6.3.4", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.10.0", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf", "react-native-plaid-link-sdk": "11.11.0", - "react-native-qrcode-svg": "git+https://github.com/Expensify/react-native-qrcode-svg", + "react-native-qrcode-svg": "git+https://github.com/Expensify/react-native-qrcode-svg-old", "react-native-quick-sqlite": "git+https://github.com/margelo/react-native-quick-sqlite#abc91857d4b3efb2020ec43abd2a508563b64316", "react-native-reanimated": "^3.8.0", "react-native-release-profiler": "^0.2.1", @@ -189,6 +189,7 @@ "@types/react-collapse": "^5.0.1", "@types/react-dom": "^18.2.4", "@types/react-is": "^18.3.0", + "@types/react-native-web": "^0.0.0", "@types/react-test-renderer": "^18.0.0", "@types/semver": "^7.5.4", "@types/setimmediate": "^1.0.2", @@ -213,11 +214,11 @@ "csv-parse": "^5.5.5", "diff-so-fancy": "^1.3.0", "dotenv": "^16.0.3", - "electron": "^29.4.1", + "electron": "^29.4.6", "electron-builder": "25.0.0", "eslint": "^8.57.0", "eslint-config-airbnb-typescript": "^18.0.0", - "eslint-config-expensify": "^2.0.52", + "eslint-config-expensify": "^2.0.58", "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "^28.6.0", "eslint-plugin-jsdoc": "^46.2.6", @@ -3951,9 +3952,9 @@ } }, "node_modules/@expensify/react-native-live-markdown": { - "version": "0.1.111", - "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.111.tgz", - "integrity": "sha512-oBRKAGA6Cv+e/D+Z5YduKL7jnD0RJC26SSyUDNMfj11Y3snG0ayi4+XKjVtfbEor9Qb/54WxM8QgEAolxcZ7Xg==", + "version": "0.1.117", + "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.117.tgz", + "integrity": "sha512-MMs8U7HRNilTc5PaCODpWL89/+fo61Np1tUBjVaiA4QQw2h5Qta8V5/YexUA4wG29M0N7gcGkxapVhfUoEB0vQ==", "workspaces": [ "parser", "example", @@ -17851,6 +17852,16 @@ "react-native": "*" } }, + "node_modules/@types/react-native-web": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@types/react-native-web/-/react-native-web-0.0.0.tgz", + "integrity": "sha512-WeaDnb57Z60pUVu6FO6WybA+7BAbPz83otLVbOpcPvRN2f/PIDt/9ViiXJ989QFrLhdex/Jen15xMOyO2X2L2A==", + "dev": true, + "dependencies": { + "@types/react": "*", + "react-native": "*" + } + }, "node_modules/@types/react-redux": { "version": "7.1.27", "license": "MIT", @@ -18109,6 +18120,186 @@ } } }, + "node_modules/@typescript-eslint/rule-tester": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/rule-tester/-/rule-tester-7.18.0.tgz", + "integrity": "sha512-ClrFQlwen9pJcYPIBLuarzBpONQAwjmJ0+YUjAo1TGzoZFJPyUK/A7bb4Mps0u+SMJJnFXbfMN8I9feQDf0O5A==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "ajv": "^6.12.6", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "4.6.2", + "semver": "^7.6.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@eslint/eslintrc": ">=2", + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/utils": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@typescript-eslint/rule-tester/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "7.13.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", @@ -23932,11 +24123,12 @@ } }, "node_modules/electron": { - "version": "29.4.1", - "resolved": "https://registry.npmjs.org/electron/-/electron-29.4.1.tgz", - "integrity": "sha512-YQvMAtdmjMF1yGfQFuO/KOmy+04SKot85NalppK/8zxKwOKrrK6dJBp+nJWteqBwRAKiasSrC1lDalF6hZct/w==", + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-29.4.6.tgz", + "integrity": "sha512-fz8ndj8cmmf441t4Yh2FDP3Rn0JhLkVGvtUf2YVMbJ5SdJPlc0JWll9jYkhh60jDKVVCr/tBAmfxqRnXMWJpzg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^20.9.0", @@ -24714,13 +24906,14 @@ } }, "node_modules/eslint-config-expensify": { - "version": "2.0.52", - "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.52.tgz", - "integrity": "sha512-TUhtgsb+EUsfqhEGhSbUVgIypEhZjloYC8PEPxKKniaaG14SW/z1G3C5E4NJQ05xVdRwJ4H+shF7ZzOYbVcraQ==", + "version": "2.0.58", + "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.58.tgz", + "integrity": "sha512-iLDJeXwMYLcBRDnInVReHWjMUsNrHMnWfyoQbvuDTChcJANc+QzuDU0gdsDpBx2xjxVF0vckwEXnzmWcUW1Bpw==", "dev": true, "dependencies": { "@lwc/eslint-plugin-lwc": "^1.7.2", "@typescript-eslint/parser": "^7.12.0", + "@typescript-eslint/rule-tester": "^7.16.1", "@typescript-eslint/utils": "^7.12.0", "babel-eslint": "^10.1.0", "eslint": "^8.56.0", @@ -25942,9 +26135,9 @@ } }, "node_modules/expensify-common": { - "version": "2.0.64", - "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.64.tgz", - "integrity": "sha512-+P9+SMPlY799b2l4A3LQ1dle+KvJXcZ01vAFxIDHni4L2Gc1QyddPKLejbwjOrkGqgl3muoR9cwuX/o+QYlYxA==", + "version": "2.0.72", + "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.72.tgz", + "integrity": "sha512-/mrlSic8y3D7pbbGMe3ZtDhHOS+WmrqgBEy3P/o9qW6CFpczs9cqjp9DfF8L53qvGtiD7cm5au4tapj01Yas/g==", "dependencies": { "awesome-phonenumber": "^5.4.0", "classnames": "2.5.0", @@ -25956,7 +26149,7 @@ "prop-types": "15.8.1", "react": "16.12.0", "react-dom": "16.12.0", - "semver": "^7.6.2", + "semver": "^7.6.3", "simply-deferred": "git+https://github.com/Expensify/simply-deferred.git#77a08a95754660c7bd6e0b6979fdf84e8e831bf5", "ua-parser-js": "^1.0.38" } @@ -37381,9 +37574,9 @@ } }, "node_modules/react-native-pager-view": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.3.tgz", - "integrity": "sha512-dqVpXWFtPNfD3D2QQQr8BP+ullS5MhjRJuF8Z/qml4QTILcrWaW8F5iAxKkQR3Jl0ikcEryG/+SQlNcwlo0Ggg==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.3.4.tgz", + "integrity": "sha512-4PEQd52EOwWcfiFJZ4VGSlY+GZfumvUzNbAozsMEgJaLvOHOMMl+Arfsc0txgtGdS49uEiHFLLZthZQzxx/Mog==", "peerDependencies": { "react": "*", "react-native": "*" @@ -37447,7 +37640,7 @@ }, "node_modules/react-native-qrcode-svg": { "version": "6.3.0", - "resolved": "git+ssh://git@github.com/Expensify/react-native-qrcode-svg.git#295f87d45c0f10d9b50838ad28fa70e47d054c3b", + "resolved": "git+ssh://git@github.com/Expensify/react-native-qrcode-svg-old.git#295f87d45c0f10d9b50838ad28fa70e47d054c3b", "dependencies": { "prop-types": "^15.8.0", "qrcode": "^1.5.1" @@ -39498,9 +39691,9 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, diff --git a/package.json b/package.json index 01e9433cd32f..8cca007e5295 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.20-4", + "version": "9.0.24-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", @@ -69,7 +69,7 @@ "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "^0.1.111", + "@expensify/react-native-live-markdown": "0.1.117", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-listformat": "^7.2.2", @@ -111,7 +111,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "2.0.64", + "expensify-common": "2.0.72", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.11.0", @@ -159,13 +159,13 @@ "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", "react-native-onyx": "2.0.64", - "react-native-pager-view": "6.2.3", + "react-native-pager-view": "6.3.4", "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.10.0", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf", "react-native-plaid-link-sdk": "11.11.0", - "react-native-qrcode-svg": "git+https://github.com/Expensify/react-native-qrcode-svg", + "react-native-qrcode-svg": "git+https://github.com/Expensify/react-native-qrcode-svg-old", "react-native-quick-sqlite": "git+https://github.com/margelo/react-native-quick-sqlite#abc91857d4b3efb2020ec43abd2a508563b64316", "react-native-reanimated": "^3.8.0", "react-native-release-profiler": "^0.2.1", @@ -245,6 +245,7 @@ "@types/react-collapse": "^5.0.1", "@types/react-dom": "^18.2.4", "@types/react-is": "^18.3.0", + "@types/react-native-web": "^0.0.0", "@types/react-test-renderer": "^18.0.0", "@types/semver": "^7.5.4", "@types/setimmediate": "^1.0.2", @@ -269,11 +270,11 @@ "csv-parse": "^5.5.5", "diff-so-fancy": "^1.3.0", "dotenv": "^16.0.3", - "electron": "^29.4.1", + "electron": "^29.4.6", "electron-builder": "25.0.0", "eslint": "^8.57.0", "eslint-config-airbnb-typescript": "^18.0.0", - "eslint-config-expensify": "^2.0.52", + "eslint-config-expensify": "^2.0.58", "eslint-config-prettier": "^9.1.0", "eslint-plugin-jest": "^28.6.0", "eslint-plugin-jsdoc": "^46.2.6", diff --git a/patches/@react-native+virtualized-lists+0.73.4+002+osr-improvement.patch b/patches/@react-native+virtualized-lists+0.73.4+002+osr-improvement.patch index dc45a6758d5c..38871a2e7764 100644 --- a/patches/@react-native+virtualized-lists+0.73.4+002+osr-improvement.patch +++ b/patches/@react-native+virtualized-lists+0.73.4+002+osr-improvement.patch @@ -1,8 +1,87 @@ diff --git a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js -index e338d90..70a59bf 100644 +index e338d90..238989f 100644 --- a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js +++ b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js -@@ -1219,7 +1219,7 @@ class VirtualizedList extends StateSafePureComponent { +@@ -89,6 +89,7 @@ type State = { + firstVisibleItemKey: ?string, + // When > 0 the scroll position available in JS is considered stale and should not be used. + pendingScrollUpdateCount: number, ++ lastItemCount: number, + }; + + function getScrollingThreshold(threshold: number, visibleLength: number) { +@@ -404,12 +405,13 @@ class VirtualizedList extends StateSafePureComponent { + + const minIndexForVisible = + this.props.maintainVisibleContentPosition?.minIndexForVisible ?? 0; ++ const itemCount = this.props.getItemCount(this.props.data); + + this.state = { + cellsAroundViewport: initialRenderRegion, + renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion), + firstVisibleItemKey: +- this.props.getItemCount(this.props.data) > minIndexForVisible ++ itemCount > minIndexForVisible + ? VirtualizedList._getItemKey(this.props, minIndexForVisible) + : null, + // When we have a non-zero initialScrollIndex, we will receive a +@@ -420,6 +422,7 @@ class VirtualizedList extends StateSafePureComponent { + this.props.initialScrollIndex > 0 + ? 1 + : 0, ++ lastItemCount: itemCount, + }; + } + +@@ -701,16 +704,15 @@ class VirtualizedList extends StateSafePureComponent { + // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make + // sure we're rendering a reasonable range here. + const itemCount = newProps.getItemCount(newProps.data); +- if (itemCount === prevState.renderMask.numCells()) { ++ if (itemCount === prevState.renderMask.numCells() && itemCount === prevState.lastItemCount) { + return prevState; + } +- + let maintainVisibleContentPositionAdjustment: ?number = null; + const prevFirstVisibleItemKey = prevState.firstVisibleItemKey; + const minIndexForVisible = + newProps.maintainVisibleContentPosition?.minIndexForVisible ?? 0; + const newFirstVisibleItemKey = +- newProps.getItemCount(newProps.data) > minIndexForVisible ++ itemCount > minIndexForVisible + ? VirtualizedList._getItemKey(newProps, minIndexForVisible) + : null; + if ( +@@ -758,6 +760,7 @@ class VirtualizedList extends StateSafePureComponent { + maintainVisibleContentPositionAdjustment != null + ? prevState.pendingScrollUpdateCount + 1 + : prevState.pendingScrollUpdateCount, ++ lastItemCount: itemCount, + }; + } + +@@ -1159,7 +1162,7 @@ class VirtualizedList extends StateSafePureComponent { + } + } + +- componentDidUpdate(prevProps: Props) { ++ componentDidUpdate(prevProps: Props, prevState: State) { + const {data, extraData} = this.props; + if (data !== prevProps.data || extraData !== prevProps.extraData) { + // clear the viewableIndices cache to also trigger +@@ -1181,6 +1184,11 @@ class VirtualizedList extends StateSafePureComponent { + if (hiPriInProgress) { + this._hiPriInProgress = false; + } ++ ++ if (this.state.cellsAroundViewport.first !== prevState.cellsAroundViewport.first || ++ this.state.cellsAroundViewport.last !== prevState.cellsAroundViewport.last) { ++ this._maybeCallOnEdgeReached(); ++ } + } + + _cellRefs: {[string]: null | CellRenderer} = {}; +@@ -1219,7 +1227,7 @@ class VirtualizedList extends StateSafePureComponent { zoomScale: 1, }; _scrollRef: ?React.ElementRef = null; @@ -11,7 +90,7 @@ index e338d90..70a59bf 100644 _sentEndForContentLength = 0; _updateCellsToRenderBatcher: Batchinator; _viewabilityTuples: Array = []; -@@ -1550,16 +1550,16 @@ class VirtualizedList extends StateSafePureComponent { +@@ -1550,16 +1558,16 @@ class VirtualizedList extends StateSafePureComponent { onStartReached != null && this.state.cellsAroundViewport.first === 0 && isWithinStartThreshold && diff --git a/patches/react-native+0.73.4+016+iOSCoreAnimationBorderRendering.patch b/patches/react-native+0.73.4+016+iOSCoreAnimationBorderRendering.patch index b59729e79622..478e282e387d 100644 --- a/patches/react-native+0.73.4+016+iOSCoreAnimationBorderRendering.patch +++ b/patches/react-native+0.73.4+016+iOSCoreAnimationBorderRendering.patch @@ -1,22 +1,23 @@ diff --git a/node_modules/react-native/React/Fabric/Mounting/RCTMountingManager.mm b/node_modules/react-native/React/Fabric/Mounting/RCTMountingManager.mm -index b4cfb3d..7aa00e5 100644 +index b4cfb3d..fdfae56 100644 --- a/node_modules/react-native/React/Fabric/Mounting/RCTMountingManager.mm +++ b/node_modules/react-native/React/Fabric/Mounting/RCTMountingManager.mm -@@ -49,6 +49,9 @@ static void RCTPerformMountInstructions( - { - SystraceSection s("RCTPerformMountInstructions"); +@@ -265,6 +265,9 @@ static void RCTPerformMountInstructions( + auto surfaceId = mountingCoordinator.getSurfaceId(); + + [CATransaction begin]; + [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; + - for (const auto &mutation : mutations) { - switch (mutation.type) { - case ShadowViewMutation::Create: { -@@ -147,6 +150,7 @@ static void RCTPerformMountInstructions( - } - } - } + mountingCoordinator.getTelemetryController().pullTransaction( + [&](const MountingTransaction &transaction, const SurfaceTelemetry &surfaceTelemetry) { + [self.delegate mountingManager:self willMountComponentsWithRootTag:surfaceId]; +@@ -278,6 +281,8 @@ static void RCTPerformMountInstructions( + _observerCoordinator.notifyObserversMountingTransactionDidMount(transaction, surfaceTelemetry); + [self.delegate mountingManager:self didMountComponentsWithRootTag:surfaceId]; + }); ++ + [CATransaction commit]; } - @implementation RCTMountingManager { + - (void)setIsJSResponder:(BOOL)isJSResponder diff --git a/patches/react-native+0.73.4+024+fixMVCPAndroid.patch b/patches/react-native+0.73.4+024+fixMVCPAndroid.patch new file mode 100644 index 000000000000..fe37e38c3040 --- /dev/null +++ b/patches/react-native+0.73.4+024+fixMVCPAndroid.patch @@ -0,0 +1,334 @@ +diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java +index fff761f..2cebd6b 100644 +--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java ++++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.java +@@ -82,6 +82,7 @@ public class MaintainVisibleScrollPositionHelper currentScroll || i == contentView.getChildCount() - 1) { +- mFirstVisibleView = new WeakReference<>(child); +- Rect frame = new Rect(); +- child.getHitRect(frame); +- mPrevFirstVisibleFrame = frame; +- break; ++ if ((position > currentScroll && position < firstVisibleViewPosition) || ++ (firstVisibleView == null && i == contentView.getChildCount() - 1)) { ++ firstVisibleView = child; ++ firstVisibleViewPosition = position; ++ } ++ } ++ mFirstVisibleView = new WeakReference<>(firstVisibleView); ++ } ++ ++ private View getFirstVisibleView() { ++ return mFirstVisibleView != null ? mFirstVisibleView.get() : null; ++ } ++ ++ private void willMountItemsInternal() { ++ View firstVisibleView = getFirstVisibleView(); ++ ++ // If we don't have a first visible view because no scroll happened call onScroll ++ // to update it. ++ if (firstVisibleView == null) { ++ onScroll(); ++ firstVisibleView = getFirstVisibleView(); ++ ++ // There are cases where it is possible for this to still be null so just bail out. ++ if (firstVisibleView == null) { ++ return; + } + } ++ Rect frame = new Rect(); ++ firstVisibleView.getHitRect(frame); ++ mPrevFirstVisibleFrame = frame; + } + + // UIManagerListener +@@ -177,19 +205,19 @@ public class MaintainVisibleScrollPositionHelper void; getAccDistancePerDirection: (gestureState: PanResponderGestureState) => number; diff --git a/node_modules/react-native-modal/dist/modal.js b/node_modules/react-native-modal/dist/modal.js -index 80f4e75..5a58eae 100644 +index 80f4e75..602cdff 100644 --- a/node_modules/react-native-modal/dist/modal.js +++ b/node_modules/react-native-modal/dist/modal.js -@@ -75,6 +75,13 @@ export class ReactNativeModal extends React.Component { +@@ -59,6 +59,11 @@ export class ReactNativeModal extends React.Component { + deviceHeight: Dimensions.get('window').height, + isSwipeable: !!this.props.swipeDirection, + pan: null, ++ backdrop: { ++ prevOpacity: 0, ++ opacity: 0, ++ }, ++ contentAnimation: {}, + }; + this.isTransitioning = false; + this.inSwipeClosingState = false; +@@ -75,6 +80,13 @@ export class ReactNativeModal extends React.Component { } return false; }; @@ -28,7 +40,202 @@ index 80f4e75..5a58eae 100644 this.shouldPropagateSwipe = (evt, gestureState) => { return typeof this.props.propagateSwipe === 'function' ? this.props.propagateSwipe(evt, gestureState) -@@ -453,10 +460,18 @@ export class ReactNativeModal extends React.Component { +@@ -134,10 +146,12 @@ export class ReactNativeModal extends React.Component { + if (this.isSwipeDirectionAllowed(gestureState)) { + // Dim the background while swiping the modal + const newOpacityFactor = 1 - this.calcDistancePercentage(gestureState); +- this.backdropRef && +- this.backdropRef.transitionTo({ +- opacity: this.props.backdropOpacity * newOpacityFactor, +- }); ++ this.setState((prevState) => ({ ++ backdrop: { ++ prevOpacity: prevState.backdrop.opacity, ++ opacity: newOpacityFactor * this.props.backdropOpacity, ++ } ++ })) + animEvt(evt, gestureState); + if (this.props.onSwipeMove) { + this.props.onSwipeMove(newOpacityFactor, gestureState); +@@ -185,11 +199,13 @@ export class ReactNativeModal extends React.Component { + if (this.props.onSwipeCancel) { + this.props.onSwipeCancel(gestureState); + } +- if (this.backdropRef) { +- this.backdropRef.transitionTo({ ++ this.setState((prevState) => ({ ++ backdrop: { ++ prevOpacity: prevState.backdrop.opacity, + opacity: this.props.backdropOpacity, +- }); +- } ++ duration: undefined, ++ } ++ })) + Animated.spring(this.state.pan, { + toValue: { x: 0, y: 0 }, + bounciness: 0, +@@ -300,40 +316,53 @@ export class ReactNativeModal extends React.Component { + } + } + }; ++ this.onContentAnimationEnd = () => { ++ this.isTransitioning = false; ++ ++ if (this.interactionHandle) { ++ InteractionManager.clearInteractionHandle(this.interactionHandle); ++ this.interactionHandle = null; ++ } ++ if (!this.props.isVisible) { ++ this.setState({ ++ showContent: false, ++ }, () => { ++ this.setState({ ++ isVisible: false, ++ }, () => { ++ this.props.onModalHide(); ++ }); ++ }); ++ } else { ++ this.props.onModalShow(); ++ } ++ } + this.open = () => { + if (this.isTransitioning) { + return; + } + this.isTransitioning = true; +- if (this.backdropRef) { +- this.backdropRef.transitionTo({ opacity: this.props.backdropOpacity }, this.props.backdropTransitionInTiming); +- } ++ ++ this.setState((prevState) => ({ ++ backdrop: { ++ prevOpacity: prevState.backdrop.opacity, ++ opacity: this.props.backdropOpacity, ++ duration: this.props.backdropTransitionInTiming, ++ }, ++ contentAnimation: { ++ animation: this.animationIn, ++ duration: this.props.animationInTiming, ++ } ++ })) + // This is for resetting the pan position,otherwise the modal gets stuck + // at the last released position when you try to open it. + // TODO: Could certainly be improved - no idea for the moment. + if (this.state.isSwipeable) { + this.state.pan.setValue({ x: 0, y: 0 }); + } +- if (this.contentRef) { +- this.props.onModalWillShow && this.props.onModalWillShow(); +- if (this.interactionHandle == null) { +- this.interactionHandle = InteractionManager.createInteractionHandle(); +- } +- this.contentRef +- .animate(this.animationIn, this.props.animationInTiming) +- .then(() => { +- this.isTransitioning = false; +- if (this.interactionHandle) { +- InteractionManager.clearInteractionHandle(this.interactionHandle); +- this.interactionHandle = null; +- } +- if (!this.props.isVisible) { +- this.close(); +- } +- else { +- this.props.onModalShow(); +- } +- }); ++ this.props.onModalWillShow && this.props.onModalWillShow(); ++ if (this.interactionHandle === null) { ++ this.interactionHandle = InteractionManager.createInteractionHandle(); + } + }; + this.close = () => { +@@ -341,9 +370,6 @@ export class ReactNativeModal extends React.Component { + return; + } + this.isTransitioning = true; +- if (this.backdropRef) { +- this.backdropRef.transitionTo({ opacity: 0 }, this.props.backdropTransitionOutTiming); +- } + let animationOut = this.animationOut; + if (this.inSwipeClosingState) { + this.inSwipeClosingState = false; +@@ -360,35 +386,22 @@ export class ReactNativeModal extends React.Component { + animationOut = 'slideOutLeft'; + } + } +- if (this.contentRef) { +- this.props.onModalWillHide && this.props.onModalWillHide(); +- if (this.interactionHandle == null) { +- this.interactionHandle = InteractionManager.createInteractionHandle(); +- } +- this.contentRef +- .animate(animationOut, this.props.animationOutTiming) +- .then(() => { +- this.isTransitioning = false; +- if (this.interactionHandle) { +- InteractionManager.clearInteractionHandle(this.interactionHandle); +- this.interactionHandle = null; +- } +- if (this.props.isVisible) { +- this.open(); +- } +- else { +- this.setState({ +- showContent: false, +- }, () => { +- this.setState({ +- isVisible: false, +- }, () => { +- this.props.onModalHide(); +- }); +- }); +- } +- }); ++ this.props.onModalWillHide && this.props.onModalWillHide(); ++ if (this.interactionHandle == null) { ++ this.interactionHandle = InteractionManager.createInteractionHandle(); + } ++ ++ this.setState((prevState) => ({ ++ backdrop: { ++ prevOpacity: prevState.backdrop.opacity, ++ opacity: 0, ++ duration: this.props.backdropTransitionOutTiming, ++ }, ++ contentAnimation: { ++ animation: animationOut, ++ duration: this.props.animationOutTiming, ++ } ++ })) + }; + this.makeBackdrop = () => { + if (!this.props.hasBackdrop) { +@@ -409,9 +422,20 @@ export class ReactNativeModal extends React.Component { + : 'transparent', + }, + ]; ++ const animation = this.state.backdrop.opacity !== this.state.backdrop.prevOpacity ? { ++ from: { ++ opacity: this.state.backdrop.prevOpacity, ++ }, ++ to: { ++ opacity: this.state.backdrop.opacity, ++ } ++ } : undefined; + const backdropWrapper = (React.createElement(animatable.View, { ref: ref => (this.backdropRef = ref), useNativeDriver: useNativeDriverForBackdrop !== undefined + ? useNativeDriverForBackdrop +- : useNativeDriver, style: [styles.backdrop, backdropComputedStyle] }, hasCustomBackdrop && customBackdrop)); ++ : useNativeDriver, ++ duration: this.state.backdrop.duration, ++ animation, ++ style: [styles.backdrop, backdropComputedStyle] }, hasCustomBackdrop && customBackdrop)); + if (hasCustomBackdrop) { + // The user will handle backdrop presses himself + return backdropWrapper; +@@ -453,10 +477,18 @@ export class ReactNativeModal extends React.Component { if (this.state.isVisible) { this.open(); } @@ -48,7 +255,7 @@ index 80f4e75..5a58eae 100644 if (this.didUpdateDimensionsEmitter) { this.didUpdateDimensionsEmitter.remove(); } -@@ -464,6 +479,9 @@ export class ReactNativeModal extends React.Component { +@@ -464,6 +496,9 @@ export class ReactNativeModal extends React.Component { InteractionManager.clearInteractionHandle(this.interactionHandle); this.interactionHandle = null; } @@ -58,7 +265,40 @@ index 80f4e75..5a58eae 100644 } componentDidUpdate(prevProps) { // If the animations have been changed then rebuild them to make sure we're -@@ -525,7 +543,7 @@ export class ReactNativeModal extends React.Component { +@@ -475,9 +510,14 @@ export class ReactNativeModal extends React.Component { + this.animationOut = animationOut; + } + // If backdrop opacity has been changed then make sure to update it +- if (this.props.backdropOpacity !== prevProps.backdropOpacity && +- this.backdropRef) { +- this.backdropRef.transitionTo({ opacity: this.props.backdropOpacity }, this.props.backdropTransitionInTiming); ++ if (this.props.backdropOpacity !== prevProps.backdropOpacity) { ++ this.setState((prevState) => ({ ++ backdrop: { ++ prevOpacity: prevState.backdrop.opacity, ++ opacity: this.props.backdropOpacity, ++ duration: this.props.backdropTransitionInTiming, ++ } ++ })) + } + // On modal open request, we slide the view up and fade in the backdrop + if (this.props.isVisible && !prevProps.isVisible) { +@@ -515,7 +555,13 @@ export class ReactNativeModal extends React.Component { + const _children = this.props.hideModalContentWhileAnimating && + this.props.useNativeDriver && + !this.state.showContent ? (React.createElement(animatable.View, null)) : (children); +- const containerView = (React.createElement(animatable.View, Object.assign({}, panHandlers, { ref: ref => (this.contentRef = ref), style: [panPosition, computedStyle], pointerEvents: "box-none", useNativeDriver: useNativeDriver }, containerProps), _children)); ++ const containerView = (React.createElement(animatable.View, Object.assign({}, panHandlers, { ++ ref: ref => (this.contentRef = ref), style: [panPosition, computedStyle], ++ pointerEvents: "box-none", useNativeDriver: useNativeDriver, ++ animation: this.state.contentAnimation.animation, ++ duration: this.state.contentAnimation.duration, ++ onAnimationEnd: this.onContentAnimationEnd, ++ }, containerProps), _children)); + // If coverScreen is set to false by the user + // we render the modal inside the parent view directly + if (!coverScreen && this.state.isVisible) { +@@ -525,7 +571,7 @@ export class ReactNativeModal extends React.Component { } return (React.createElement(Modal, Object.assign({ transparent: true, animationType: 'none', visible: this.state.isVisible, onRequestClose: onBackButtonPress }, otherProps), this.makeBackdrop(), diff --git a/patches/react-native-web+0.19.12+005+osr-improvement.patch b/patches/react-native-web+0.19.12+005+osr-improvement.patch index 074cac3d0e6f..b1afa699e7a2 100644 --- a/patches/react-native-web+0.19.12+005+osr-improvement.patch +++ b/patches/react-native-web+0.19.12+005+osr-improvement.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js -index b05da08..80aea85 100644 +index bede95b..2aef4c6 100644 --- a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js +++ b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js @@ -332,7 +332,7 @@ class VirtualizedList extends StateSafePureComponent { @@ -11,7 +11,75 @@ index b05da08..80aea85 100644 this._sentEndForContentLength = 0; this._totalCellLength = 0; this._totalCellsMeasured = 0; -@@ -1397,8 +1397,8 @@ class VirtualizedList extends StateSafePureComponent { +@@ -684,16 +684,18 @@ class VirtualizedList extends StateSafePureComponent { + }); + } + } ++ var itemCount = this.props.getItemCount(this.props.data); + var initialRenderRegion = VirtualizedList._initialRenderRegion(_props); + var minIndexForVisible = (_this$props$maintainV = (_this$props$maintainV2 = this.props.maintainVisibleContentPosition) == null ? void 0 : _this$props$maintainV2.minIndexForVisible) !== null && _this$props$maintainV !== void 0 ? _this$props$maintainV : 0; + this.state = { + cellsAroundViewport: initialRenderRegion, + renderMask: VirtualizedList._createRenderMask(_props, initialRenderRegion), +- firstVisibleItemKey: this.props.getItemCount(this.props.data) > minIndexForVisible ? VirtualizedList._getItemKey(this.props, minIndexForVisible) : null, ++ firstVisibleItemKey: itemCount > minIndexForVisible ? VirtualizedList._getItemKey(this.props, minIndexForVisible) : null, + // When we have a non-zero initialScrollIndex, we will receive a + // scroll event later so this will prevent the window from updating + // until we get a valid offset. +- pendingScrollUpdateCount: this.props.initialScrollIndex != null && this.props.initialScrollIndex > 0 ? 1 : 0 ++ pendingScrollUpdateCount: this.props.initialScrollIndex != null && this.props.initialScrollIndex > 0 ? 1 : 0, ++ lastItemCount: itemCount + }; + + // REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller. +@@ -919,13 +921,13 @@ class VirtualizedList extends StateSafePureComponent { + // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make + // sure we're rendering a reasonable range here. + var itemCount = newProps.getItemCount(newProps.data); +- if (itemCount === prevState.renderMask.numCells()) { ++ if (itemCount === prevState.renderMask.numCells() && itemCount === prevState.lastItemCount) { + return prevState; + } + var maintainVisibleContentPositionAdjustment = null; + var prevFirstVisibleItemKey = prevState.firstVisibleItemKey; + var minIndexForVisible = (_newProps$maintainVis = (_newProps$maintainVis2 = newProps.maintainVisibleContentPosition) == null ? void 0 : _newProps$maintainVis2.minIndexForVisible) !== null && _newProps$maintainVis !== void 0 ? _newProps$maintainVis : 0; +- var newFirstVisibleItemKey = newProps.getItemCount(newProps.data) > minIndexForVisible ? VirtualizedList._getItemKey(newProps, minIndexForVisible) : null; ++ var newFirstVisibleItemKey = itemCount > minIndexForVisible ? VirtualizedList._getItemKey(newProps, minIndexForVisible) : null; + if (newProps.maintainVisibleContentPosition != null && prevFirstVisibleItemKey != null && newFirstVisibleItemKey != null) { + if (newFirstVisibleItemKey !== prevFirstVisibleItemKey) { + // Fast path if items were added at the start of the list. +@@ -944,7 +946,8 @@ class VirtualizedList extends StateSafePureComponent { + cellsAroundViewport: constrainedCells, + renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells), + firstVisibleItemKey: newFirstVisibleItemKey, +- pendingScrollUpdateCount: maintainVisibleContentPositionAdjustment != null ? prevState.pendingScrollUpdateCount + 1 : prevState.pendingScrollUpdateCount ++ pendingScrollUpdateCount: maintainVisibleContentPositionAdjustment != null ? prevState.pendingScrollUpdateCount + 1 : prevState.pendingScrollUpdateCount, ++ lastItemCount: itemCount + }; + } + _pushCells(cells, stickyHeaderIndices, stickyIndicesFromProps, first, last, inversionStyle) { +@@ -1220,7 +1223,7 @@ class VirtualizedList extends StateSafePureComponent { + return ret; + } + } +- componentDidUpdate(prevProps) { ++ componentDidUpdate(prevProps, prevState) { + var _this$props7 = this.props, + data = _this$props7.data, + extraData = _this$props7.extraData; +@@ -1244,6 +1247,11 @@ class VirtualizedList extends StateSafePureComponent { + if (hiPriInProgress) { + this._hiPriInProgress = false; + } ++ ++ if (this.state.cellsAroundViewport.first !== prevState.cellsAroundViewport.first || ++ this.state.cellsAroundViewport.last !== prevState.cellsAroundViewport.last) { ++ this._maybeCallOnEdgeReached(); ++ } + } + + // Used for preventing scrollToIndex from being called multiple times for initialScrollIndex +@@ -1407,8 +1415,8 @@ class VirtualizedList extends StateSafePureComponent { // Next check if the user just scrolled within the start threshold // and call onStartReached only once for a given content length, // and only if onEndReached is not being executed @@ -22,7 +90,7 @@ index b05da08..80aea85 100644 onStartReached({ distanceFromStart }); -@@ -1407,7 +1407,7 @@ class VirtualizedList extends StateSafePureComponent { +@@ -1417,7 +1425,7 @@ class VirtualizedList extends StateSafePureComponent { // If the user scrolls away from the start or end and back again, // cause onStartReached or onEndReached to be triggered again else { @@ -32,10 +100,80 @@ index b05da08..80aea85 100644 } } diff --git a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js -index 459f017..799a6ee 100644 +index 459f017..d20115c 100644 --- a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js +++ b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js -@@ -1325,7 +1325,7 @@ class VirtualizedList extends StateSafePureComponent { +@@ -79,6 +79,7 @@ type State = { + firstVisibleItemKey: ?string, + // When > 0 the scroll position available in JS is considered stale and should not be used. + pendingScrollUpdateCount: number, ++ lastItemCount: number, + }; + + /** +@@ -453,12 +454,13 @@ class VirtualizedList extends StateSafePureComponent { + + const minIndexForVisible = + this.props.maintainVisibleContentPosition?.minIndexForVisible ?? 0; ++ const itemCount = this.props.getItemCount(this.props.data); + + this.state = { + cellsAroundViewport: initialRenderRegion, + renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion), + firstVisibleItemKey: +- this.props.getItemCount(this.props.data) > minIndexForVisible ++ itemCount > minIndexForVisible + ? VirtualizedList._getItemKey(this.props, minIndexForVisible) + : null, + // When we have a non-zero initialScrollIndex, we will receive a +@@ -469,6 +471,7 @@ class VirtualizedList extends StateSafePureComponent { + this.props.initialScrollIndex > 0 + ? 1 + : 0, ++ lastItemCount: itemCount, + }; + + // REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller. +@@ -809,16 +812,15 @@ class VirtualizedList extends StateSafePureComponent { + // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make + // sure we're rendering a reasonable range here. + const itemCount = newProps.getItemCount(newProps.data); +- if (itemCount === prevState.renderMask.numCells()) { ++ if (itemCount === prevState.renderMask.numCells() && itemCount === prevState.lastItemCount) { + return prevState; + } +- + let maintainVisibleContentPositionAdjustment: ?number = null; + const prevFirstVisibleItemKey = prevState.firstVisibleItemKey; + const minIndexForVisible = + newProps.maintainVisibleContentPosition?.minIndexForVisible ?? 0; + const newFirstVisibleItemKey = +- newProps.getItemCount(newProps.data) > minIndexForVisible ++ itemCount > minIndexForVisible + ? VirtualizedList._getItemKey(newProps, minIndexForVisible) + : null; + if ( +@@ -866,6 +868,7 @@ class VirtualizedList extends StateSafePureComponent { + maintainVisibleContentPositionAdjustment != null + ? prevState.pendingScrollUpdateCount + 1 + : prevState.pendingScrollUpdateCount, ++ lastItemCount: itemCount, + }; + } + +@@ -1285,6 +1288,11 @@ class VirtualizedList extends StateSafePureComponent { + if (hiPriInProgress) { + this._hiPriInProgress = false; + } ++ ++ if (this.state.cellsAroundViewport.first !== prevState.cellsAroundViewport.first || ++ this.state.cellsAroundViewport.last !== prevState.cellsAroundViewport.last) { ++ this._maybeCallOnEdgeReached(); ++ } + } + + _averageCellLength = 0; +@@ -1325,7 +1333,7 @@ class VirtualizedList extends StateSafePureComponent { zoomScale: 1, }; _scrollRef: ?React.ElementRef = null; @@ -44,7 +182,7 @@ index 459f017..799a6ee 100644 _sentEndForContentLength = 0; _totalCellLength = 0; _totalCellsMeasured = 0; -@@ -1675,18 +1675,18 @@ class VirtualizedList extends StateSafePureComponent { +@@ -1675,18 +1683,18 @@ class VirtualizedList extends StateSafePureComponent { onStartReached != null && this.state.cellsAroundViewport.first === 0 && isWithinStartThreshold && diff --git a/patches/react-native-web+0.19.12+007+fix-scrollable-overflown-text.patch b/patches/react-native-web+0.19.12+007+fix-scrollable-overflown-text.patch new file mode 100644 index 000000000000..11b85afcf86c --- /dev/null +++ b/patches/react-native-web+0.19.12+007+fix-scrollable-overflown-text.patch @@ -0,0 +1,26 @@ +diff --git a/node_modules/react-native-web/dist/exports/Text/index.js b/node_modules/react-native-web/dist/exports/Text/index.js +index 8c5f79b..4a47f80 100644 +--- a/node_modules/react-native-web/dist/exports/Text/index.js ++++ b/node_modules/react-native-web/dist/exports/Text/index.js +@@ -166,7 +166,7 @@ var styles = StyleSheet.create({ + textMultiLine: { + display: '-webkit-box', + maxWidth: '100%', +- overflow: 'hidden', ++ overflow: 'clip', + textOverflow: 'ellipsis', + WebkitBoxOrient: 'vertical' + }, +diff --git a/node_modules/react-native-web/src/exports/Text/index.js b/node_modules/react-native-web/src/exports/Text/index.js +index 071ae10..e43042c 100644 +--- a/node_modules/react-native-web/src/exports/Text/index.js ++++ b/node_modules/react-native-web/src/exports/Text/index.js +@@ -219,7 +219,7 @@ const styles = StyleSheet.create({ + textMultiLine: { + display: '-webkit-box', + maxWidth: '100%', +- overflow: 'hidden', ++ overflow: 'clip', + textOverflow: 'ellipsis', + WebkitBoxOrient: 'vertical' + }, diff --git a/src/CONST.ts b/src/CONST.ts index f1e4a3bb46d5..93d2921e704f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -86,6 +86,7 @@ const CONST = { DEFAULT_TABLE_NAME: 'keyvaluepairs', DEFAULT_ONYX_DUMP_FILE_NAME: 'onyx-state.txt', DEFAULT_POLICY_ROOM_CHAT_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL], + DISABLED_MAX_EXPENSE_VALUE: 10000000000, // Note: Group and Self-DM excluded as these are not tied to a Workspace WORKSPACE_ROOM_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL, chatTypes.POLICY_ROOM, chatTypes.POLICY_EXPENSE_CHAT], @@ -355,6 +356,7 @@ const CONST = { OPEN: 'OPEN', }, MAX_LENGTH: { + FULL_SSN: 9, SSN: 4, ZIP_CODE: 10, }, @@ -381,6 +383,7 @@ const CONST = { REPORT_FIELDS_FEATURE: 'reportFieldsFeature', WORKSPACE_FEEDS: 'workspaceFeeds', NETSUITE_USA_TAX: 'netsuiteUsaTax', + WORKSPACE_RULES: 'workspaceRules', }, BUTTON_STATES: { DEFAULT: 'default', @@ -708,6 +711,7 @@ const CONST = { FORWARDED: 'FORWARDED', // OldDot Action HOLD: 'HOLD', HOLD_COMMENT: 'HOLDCOMMENT', + INTEGRATION_SYNC_FAILED: 'INTEGRATIONSYNCFAILED', IOU: 'IOU', INTEGRATIONS_MESSAGE: 'INTEGRATIONSMESSAGE', // OldDot Action MANAGER_ATTACH_RECEIPT: 'MANAGERATTACHRECEIPT', // OldDot Action @@ -911,6 +915,7 @@ const CONST = { WRITE: 'write', SHARE: 'share', OWN: 'own', + AUDITOR: 'auditor', }, INVOICE_RECEIVER_TYPE: { INDIVIDUAL: 'individual', @@ -971,10 +976,11 @@ const CONST = { HOMEPAGE_INITIAL_RENDER: 'homepage_initial_render', REPORT_INITIAL_RENDER: 'report_initial_render', SWITCH_REPORT: 'switch_report', - SWITCH_REPORT_FROM_PREVIEW: 'switch_report_from_preview', - SWITCH_REPORT_THREAD: 'switch_report_thread', + OPEN_REPORT_FROM_PREVIEW: 'open_report_from_preview', + OPEN_REPORT_THREAD: 'open_report_thread', SIDEBAR_LOADED: 'sidebar_loaded', LOAD_SEARCH_OPTIONS: 'load_search_options', + MESSAGE_SENT: 'message_sent', COLD: 'cold', WARM: 'warm', REPORT_ACTION_ITEM_LAYOUT_DEBOUNCE_TIME: 1500, @@ -1187,6 +1193,7 @@ const CONST = { VISIBLE_PASSWORD: 'visible-password', ASCII_CAPABLE: 'ascii-capable', NUMBER_PAD: 'number-pad', + DECIMAL_PAD: 'decimal-pad', }, INPUT_MODE: { @@ -2081,6 +2088,7 @@ const CONST = { ARE_EXPENSIFY_CARDS_ENABLED: 'areExpensifyCardsEnabled', ARE_INVOICES_ENABLED: 'areInvoicesEnabled', ARE_TAXES_ENABLED: 'tax', + ARE_RULES_ENABLED: 'areRulesEnabled', }, DEFAULT_CATEGORIES: [ 'Advertising', @@ -2130,6 +2138,12 @@ const CONST = { NETSUITE: 'netsuite', SAGE_INTACCT: 'intacct', }, + ROUTE: { + QBO: 'quickbooks-online', + XERO: 'xero', + NETSUITE: 'netsuite', + SAGE_INTACCT: 'sage-intacct', + }, NAME_USER_FRIENDLY: { netsuite: 'NetSuite', quickbooksOnline: 'Quickbooks Online', @@ -2180,7 +2194,10 @@ const CONST = { NETSUITE_SYNC_ACCOUNTS: 'netSuiteSyncAccounts', NETSUITE_SYNC_CURRENCIES: 'netSuiteSyncCurrencies', NETSUITE_SYNC_CATEGORIES: 'netSuiteSyncCategories', + NETSUITE_SYNC_IMPORT_CUSTOM_LISTS: 'netSuiteSyncImportCustomLists', NETSUITE_SYNC_IMPORT_EMPLOYEES: 'netSuiteSyncImportEmployees', + NETSUITE_SYNC_IMPORT_SUBSIDIARIES: 'netSuiteSyncImportSubsidiaries', + NETSUITE_SYNC_IMPORT_VENDORS: 'netSuiteSyncImportVendors', NETSUITE_SYNC_REPORT_FIELDS: 'netSuiteSyncReportFields', NETSUITE_SYNC_TAGS: 'netSuiteSyncTags', NETSUITE_SYNC_UPDATE_DATA: 'netSuiteSyncUpdateConnectionData', @@ -2414,6 +2431,7 @@ const CONST = { WORKSPACE_BANK_ACCOUNT: 'WorkspaceBankAccount', WORKSPACE_SETTINGS: 'WorkspaceSettings', WORKSPACE_FEATURES: 'WorkspaceFeatures', + WORKSPACE_RULES: 'WorkspaceRules', }, get EXPENSIFY_EMAILS() { return [ @@ -3906,6 +3924,7 @@ const CONST = { }, STRIPE_GBP_AUTH_STATUSES: { SUCCEEDED: 'succeeded', + CARD_AUTHENTICATION_REQUIRED: 'authentication_required', }, TAB: { NEW_CHAT_TAB_ID: 'NewChatTab', @@ -5460,6 +5479,14 @@ const CONST = { description: 'workspace.upgrade.taxCodes.description' as const, icon: 'Coins', }, + rules: { + id: 'rules' as const, + alias: 'rules', + name: 'Rules', + title: 'workspace.upgrade.rules.title' as const, + description: 'workspace.upgrade.rules.description' as const, + icon: 'Rules', + }, }; }, REPORT_FIELD_TYPES: { diff --git a/src/Expensify.tsx b/src/Expensify.tsx index 8ec3fa194cf9..8a2ef4a2b2f4 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -41,7 +41,7 @@ import PopoverReportActionContextMenu from './pages/home/report/ContextMenu/Popo import * as ReportActionContextMenu from './pages/home/report/ContextMenu/ReportActionContextMenu'; import type {Route} from './ROUTES'; import ROUTES from './ROUTES'; -import type {ScreenShareRequest, Session} from './types/onyx'; +import type {ScreenShareRequest} from './types/onyx'; Onyx.registerLogger(({level, message}) => { if (level === 'alert') { @@ -58,9 +58,6 @@ type ExpensifyOnyxProps = { /** Whether the app is waiting for the server's response to determine if a room is public */ isCheckingPublicRoom: OnyxEntry; - /** Session info for the currently logged in user. */ - session: OnyxEntry; - /** Whether a new update is available and ready to install. */ updateAvailable: OnyxEntry; @@ -91,7 +88,6 @@ const SplashScreenHiddenContext = React.createContext { @@ -259,6 +256,7 @@ function Expensify({ {shouldInit && ( <> @@ -317,9 +315,6 @@ export default withOnyx({ key: ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, initWithStoredValues: false, }, - session: { - key: ONYXKEYS.SESSION, - }, updateAvailable: { key: ONYXKEYS.UPDATE_AVAILABLE, initWithStoredValues: false, diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8c339e9120ab..b7b6cf53a176 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -460,8 +460,8 @@ const ONYXKEYS = { SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END: 'sharedNVP_private_billingGracePeriodEnd_', /** - * Stores the card list for a given fundID and feed in the format: card__ - * So for example: card_12345_Expensify Card + * Stores the card list for a given fundID and feed in the format: cards__ + * So for example: cards_12345_Expensify Card */ WORKSPACE_CARDS_LIST: 'cards_', @@ -551,8 +551,8 @@ const ONYXKEYS = { SETTINGS_STATUS_SET_CLEAR_AFTER_FORM_DRAFT: 'settingsStatusSetClearAfterFormDraft', SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm', SETTINGS_STATUS_CLEAR_DATE_FORM_DRAFT: 'settingsStatusClearDateFormDraft', - CHANGE_BILLING_CURRENCY_FORM: 'changeBillingCurrencyForm', - CHANGE_BILLING_CURRENCY_FORM_DRAFT: 'changeBillingCurrencyFormDraft', + CHANGE_BILLING_CURRENCY_FORM: 'billingCurrencyForm', + CHANGE_BILLING_CURRENCY_FORM_DRAFT: 'billingCurrencyFormDraft', PRIVATE_NOTES_FORM: 'privateNotesForm', PRIVATE_NOTES_FORM_DRAFT: 'privateNotesFormDraft', I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm', @@ -571,6 +571,10 @@ const ONYXKEYS = { REIMBURSEMENT_ACCOUNT_FORM_DRAFT: 'reimbursementAccountDraft', PERSONAL_BANK_ACCOUNT_FORM: 'personalBankAccount', PERSONAL_BANK_ACCOUNT_FORM_DRAFT: 'personalBankAccountDraft', + DISABLE_AUTO_RENEW_SURVEY_FORM: 'disableAutoRenewSurveyForm', + DISABLE_AUTO_RENEW_SURVEY_FORM_DRAFT: 'disableAutoRenewSurveyFormDraft', + REQUEST_EARLY_CANCELLATION_FORM: 'requestEarlyCancellationForm', + REQUEST_EARLY_CANCELLATION_FORM_DRAFT: 'requestEarlyCancellationFormDraft', EXIT_SURVEY_REASON_FORM: 'exitSurveyReasonForm', EXIT_SURVEY_REASON_FORM_DRAFT: 'exitSurveyReasonFormDraft', EXIT_SURVEY_RESPONSE_FORM: 'exitSurveyResponseForm', @@ -647,6 +651,8 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.ROOM_SETTINGS_FORM]: FormTypes.RoomSettingsForm; [ONYXKEYS.FORMS.NEW_TASK_FORM]: FormTypes.NewTaskForm; [ONYXKEYS.FORMS.EDIT_TASK_FORM]: FormTypes.EditTaskForm; + [ONYXKEYS.FORMS.DISABLE_AUTO_RENEW_SURVEY_FORM]: FormTypes.FeedbackSurveyForm; + [ONYXKEYS.FORMS.REQUEST_EARLY_CANCELLATION_FORM]: FormTypes.FeedbackSurveyForm; [ONYXKEYS.FORMS.EXIT_SURVEY_REASON_FORM]: FormTypes.ExitSurveyReasonForm; [ONYXKEYS.FORMS.EXIT_SURVEY_RESPONSE_FORM]: FormTypes.ExitSurveyResponseForm; [ONYXKEYS.FORMS.MONEY_REQUEST_DESCRIPTION_FORM]: FormTypes.MoneyRequestDescriptionForm; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index de495568daa3..73271d85ea49 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -44,6 +44,7 @@ const ROUTES = { SEARCH_ADVANCED_FILTERS_MERCHANT: 'search/filters/merchant', SEARCH_ADVANCED_FILTERS_DESCRIPTION: 'search/filters/description', SEARCH_ADVANCED_FILTERS_REPORT_ID: 'search/filters/reportID', + SEARCH_ADVANCED_FILTERS_AMOUNT: 'search/filters/amount', SEARCH_ADVANCED_FILTERS_CATEGORY: 'search/filters/category', SEARCH_ADVANCED_FILTERS_KEYWORD: 'search/filters/keyword', SEARCH_ADVANCED_FILTERS_CARD: 'search/filters/card', @@ -193,7 +194,7 @@ const ROUTES = { }, SETTINGS_CONTACT_METHOD_DETAILS: { route: 'settings/profile/contact-methods/:contactMethod/details', - getRoute: (contactMethod: string) => `settings/profile/contact-methods/${encodeURIComponent(contactMethod)}/details` as const, + getRoute: (contactMethod: string, backTo?: string) => getUrlWithBackToParam(`settings/profile/contact-methods/${encodeURIComponent(contactMethod)}/details`, backTo), }, SETTINGS_NEW_CONTACT_METHOD: { route: 'settings/profile/contact-methods/new', @@ -349,7 +350,7 @@ const ROUTES = { }, ROOM_INVITE: { route: 'r/:reportID/invite/:role?', - getRoute: (reportID: string, role?: string) => `r/${reportID}/invite/${role}` as const, + getRoute: (reportID: string, role?: string) => `r/${reportID}/invite/${role ?? ''}` as const, }, MONEY_REQUEST_HOLD_REASON: { route: ':type/edit/reason/:transactionID?', @@ -717,11 +718,12 @@ const ROUTES = { }, WORKSPACE_ACCOUNTING_CARD_RECONCILIATION: { route: 'settings/workspaces/:policyID/accounting/:connection/card-reconciliation', - getRoute: (policyID: string, connection?: ConnectionName) => `settings/workspaces/${policyID}/accounting/${connection}/card-reconciliation` as const, + getRoute: (policyID: string, connection?: ValueOf) => `settings/workspaces/${policyID}/accounting/${connection}/card-reconciliation` as const, }, WORKSPACE_ACCOUNTING_RECONCILIATION_ACCOUNT_SETTINGS: { route: 'settings/workspaces/:policyID/accounting/:connection/card-reconciliation/account', - getRoute: (policyID: string, connection?: ConnectionName) => `settings/workspaces/${policyID}/accounting/${connection}/card-reconciliation/account` as const, + getRoute: (policyID: string, connection?: ValueOf) => + `settings/workspaces/${policyID}/accounting/${connection}/card-reconciliation/account` as const, }, WORKSPACE_CATEGORIES: { route: 'settings/workspaces/:policyID/categories', @@ -926,6 +928,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/expensify-card/settings/frequency', getRoute: (policyID: string) => `settings/workspaces/${policyID}/expensify-card/settings/frequency` as const, }, + WORKSPACE_RULES: { + route: 'settings/workspaces/:policyID/rules', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/rules` as const, + }, WORKSPACE_DISTANCE_RATES: { route: 'settings/workspaces/:policyID/distance-rates', getRoute: (policyID: string) => `settings/workspaces/${policyID}/distance-rates` as const, @@ -984,7 +990,7 @@ const ROUTES = { TRANSACTION_RECEIPT: { route: 'r/:reportID/transaction/:transactionID/receipt', - getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const, + getRoute: (reportID: string, transactionID: string, readonly = false) => `r/${reportID}/transaction/${transactionID}/receipt${readonly ? '?readonly=true' : ''}` as const, }, TRANSACTION_DUPLICATE_REVIEW_PAGE: { route: 'r/:threadReportID/duplicates/review', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 30adc5f89d08..142b2f80a66e 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -37,6 +37,7 @@ const SCREENS = { ADVANCED_FILTERS_DESCRIPTION_RHP: 'Search_Advanced_Filters_Description_RHP', ADVANCED_FILTERS_MERCHANT_RHP: 'Search_Advanced_Filters_Merchant_RHP', ADVANCED_FILTERS_REPORT_ID_RHP: 'Search_Advanced_Filters_ReportID_RHP', + ADVANCED_FILTERS_AMOUNT_RHP: 'Search_Advanced_Filters_Amount_RHP', ADVANCED_FILTERS_CATEGORY_RHP: 'Search_Advanced_Filters_Category_RHP', ADVANCED_FILTERS_KEYWORD_RHP: 'Search_Advanced_Filters_Keyword_RHP', ADVANCED_FILTERS_CARD_RHP: 'Search_Advanced_Filters_Card_RHP', @@ -440,6 +441,7 @@ const SCREENS = { DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT: 'Distance_Rate_Tax_Reclaimable_On_Edit', DISTANCE_RATE_TAX_RATE_EDIT: 'Distance_Rate_Tax_Rate_Edit', UPGRADE: 'Workspace_Upgrade', + RULES: 'Policy_Rules', }, EDIT_REQUEST: { diff --git a/src/components/AmountWithoutCurrencyForm.tsx b/src/components/AmountWithoutCurrencyForm.tsx new file mode 100644 index 000000000000..78b7c84ecb54 --- /dev/null +++ b/src/components/AmountWithoutCurrencyForm.tsx @@ -0,0 +1,66 @@ +import React, {useCallback, useMemo} from 'react'; +import type {ForwardedRef} from 'react'; +import useLocalize from '@hooks/useLocalize'; +import {addLeadingZero, replaceAllDigits, replaceCommasWithPeriod, stripSpacesFromAmount, validateAmount} from '@libs/MoneyRequestUtils'; +import CONST from '@src/CONST'; +import TextInput from './TextInput'; +import type {BaseTextInputProps, BaseTextInputRef} from './TextInput/BaseTextInput/types'; + +type AmountFormProps = { + /** Amount supplied by the FormProvider */ + value?: string; + + /** Callback to update the amount in the FormProvider */ + onInputChange?: (value: string) => void; +} & Partial; + +function AmountWithoutCurrencyForm( + {value: amount, onInputChange, inputID, name, defaultValue, accessibilityLabel, role, label, ...rest}: AmountFormProps, + ref: ForwardedRef, +) { + const {toLocaleDigit} = useLocalize(); + + const currentAmount = useMemo(() => (typeof amount === 'string' ? amount : ''), [amount]); + + /** + * Sets the selection and the amount accordingly to the value passed to the input + * @param newAmount - Changed amount from user input + */ + const setNewAmount = useCallback( + (newAmount: string) => { + // Remove spaces from the newAmount value because Safari on iOS adds spaces when pasting a copied value + // More info: https://github.com/Expensify/App/issues/16974 + const newAmountWithoutSpaces = stripSpacesFromAmount(newAmount); + const replacedCommasAmount = replaceCommasWithPeriod(newAmountWithoutSpaces); + const withLeadingZero = addLeadingZero(replacedCommasAmount); + if (!validateAmount(withLeadingZero, 2)) { + return; + } + onInputChange?.(withLeadingZero); + }, + [onInputChange], + ); + + const formattedAmount = replaceAllDigits(currentAmount, toLocaleDigit); + + return ( + + ); +} + +AmountWithoutCurrencyForm.displayName = 'AmountWithoutCurrencyForm'; + +export default React.forwardRef(AmountWithoutCurrencyForm); diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index 164da5922b98..28f44aabb068 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -422,13 +422,20 @@ function AttachmentModal({ onSelected: () => downloadAttachment(), }); } - if (TransactionUtils.hasReceipt(transaction) && !TransactionUtils.isReceiptBeingScanned(transaction) && canEditReceipt && !TransactionUtils.hasMissingSmartscanFields(transaction)) { + if ( + !TransactionUtils.hasEReceipt(transaction) && + TransactionUtils.hasReceipt(transaction) && + !TransactionUtils.isReceiptBeingScanned(transaction) && + canEditReceipt && + !TransactionUtils.hasMissingSmartscanFields(transaction) + ) { menuItems.push({ icon: Expensicons.Trashcan, text: translate('receipt.deleteReceipt'), onSelected: () => { setIsDeleteReceiptConfirmModalVisible(true); }, + shouldCallAfterModalHide: true, }); } return menuItems; diff --git a/src/components/AttachmentPicker/index.tsx b/src/components/AttachmentPicker/index.tsx index 669b26724a02..26d117697888 100644 --- a/src/components/AttachmentPicker/index.tsx +++ b/src/components/AttachmentPicker/index.tsx @@ -1,4 +1,5 @@ import React, {useRef} from 'react'; +import type {ValueOf} from 'type-fest'; import Visibility from '@libs/Visibility'; import CONST from '@src/CONST'; import type AttachmentPickerProps from './types'; @@ -14,6 +15,25 @@ function getAcceptableFileTypes(type: string): string | undefined { return 'image/*'; } +function getAcceptableFileTypesFromAList(fileTypes: Array>): string { + const acceptValue = fileTypes + .map((type) => { + switch (type) { + case 'msword': + return 'application/msword'; + case 'text': + return 'text/plain'; + case 'message': + return 'message/rfc822'; + default: + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + return `.${type}`; + } + }) + .join(','); + return acceptValue; +} + /** * This component renders a function as a child and * returns a "show attachment picker" method that takes @@ -21,7 +41,7 @@ function getAcceptableFileTypes(type: string): string | undefined { * on a Browser we must append a hidden input to the DOM * and listen to onChange event. */ -function AttachmentPicker({children, type = CONST.ATTACHMENT_PICKER_TYPE.FILE}: AttachmentPickerProps): React.JSX.Element { +function AttachmentPicker({children, type = CONST.ATTACHMENT_PICKER_TYPE.FILE, acceptedFileTypes}: AttachmentPickerProps): React.JSX.Element { const fileInput = useRef(null); const onPicked = useRef<(file: File) => void>(() => {}); const onCanceled = useRef<() => void>(() => {}); @@ -75,7 +95,7 @@ function AttachmentPicker({children, type = CONST.ATTACHMENT_PICKER_TYPE.FILE}: {once: true}, ); }} - accept={getAcceptableFileTypes(type)} + accept={acceptedFileTypes ? getAcceptableFileTypesFromAList(acceptedFileTypes) : getAcceptableFileTypes(type)} /> {children({ openPicker: ({onPicked: newOnPicked, onCanceled: newOnCanceled = () => {}}) => { diff --git a/src/components/AttachmentPicker/types.ts b/src/components/AttachmentPicker/types.ts index 445d79bce07a..057ec72de27e 100644 --- a/src/components/AttachmentPicker/types.ts +++ b/src/components/AttachmentPicker/types.ts @@ -40,6 +40,8 @@ type AttachmentPickerProps = { /** The types of files that can be selected with this picker. */ type?: ValueOf; + + acceptedFileTypes?: Array>; }; export default AttachmentPickerProps; diff --git a/src/components/AvatarWithImagePicker.tsx b/src/components/AvatarWithImagePicker.tsx index a1b8524dd293..8a018101b63e 100644 --- a/src/components/AvatarWithImagePicker.tsx +++ b/src/components/AvatarWithImagePicker.tsx @@ -11,7 +11,6 @@ import * as FileUtils from '@libs/fileDownload/FileUtils'; import getImageResolution from '@libs/fileDownload/getImageResolution'; import type {AvatarSource} from '@libs/UserUtils'; import variables from '@styles/variables'; -import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; @@ -44,6 +43,7 @@ type MenuItem = { icon: IconAsset; text: string; onSelected: () => void; + shouldCallAfterModalHide?: boolean; }; type AvatarWithImagePickerProps = { @@ -260,19 +260,19 @@ function AvatarWithImagePicker({ * Create menu items list for avatar menu */ const createMenuItems = (openPicker: OpenPicker): MenuItem[] => { - const menuItems = [ + const menuItems: MenuItem[] = [ { icon: Expensicons.Upload, text: translate('avatarWithImagePicker.uploadPhoto'), - onSelected: () => - Modal.close(() => { - if (Browser.isSafari()) { - return; - } - openPicker({ - onPicked: showAvatarCropModal, - }); - }), + onSelected: () => { + if (Browser.isSafari()) { + return; + } + openPicker({ + onPicked: showAvatarCropModal, + }); + }, + shouldCallAfterModalHide: true, }, ]; @@ -344,14 +344,14 @@ function AvatarWithImagePicker({ menuItems.push({ icon: Expensicons.Eye, text: translate('avatarWithImagePicker.viewPhoto'), - onSelected: () => - Modal.close(() => { - if (typeof onViewPhotoPress !== 'function') { - show(); - return; - } - onViewPhotoPress(); - }), + onSelected: () => { + if (typeof onViewPhotoPress !== 'function') { + show(); + return; + } + onViewPhotoPress(); + }, + shouldCallAfterModalHide: true, }); } diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index f6096e3b55e8..f4e1b992437f 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -1,8 +1,9 @@ import type {ImageContentFit} from 'expo-image'; import React, {useMemo} from 'react'; -import type {ImageSourcePropType, StyleProp, TextStyle, ViewStyle, WebStyle} from 'react-native'; +import type {ImageSourcePropType, StyleProp, TextStyle, ViewStyle} from 'react-native'; import {View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; +import type {WebStyle} from 'react-native-web'; import type {MergeExclusive} from 'type-fest'; import AutoEmailLink from '@components/AutoEmailLink'; import Icon from '@components/Icon'; diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 943d6dbb5c16..74b38f515a06 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -11,7 +11,6 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import mergeRefs from '@libs/mergeRefs'; -import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; import type {AnchorPosition} from '@src/styles'; import type {ButtonWithDropdownMenuProps} from './types'; @@ -178,11 +177,12 @@ function ButtonWithDropdownMenu({ menuItems={options.map((item, index) => ({ ...item, onSelected: item.onSelected - ? () => Modal.close(() => item.onSelected?.()) + ? () => item.onSelected?.() : () => { onOptionSelected?.(item); setSelectedItemIndex(index); }, + shouldCallAfterModalHide: true, }))} /> )} diff --git a/src/components/Composer/index.native.tsx b/src/components/Composer/index.native.tsx index b801743732bc..a2fcae901681 100644 --- a/src/components/Composer/index.native.tsx +++ b/src/components/Composer/index.native.tsx @@ -1,11 +1,12 @@ import type {MarkdownStyle} from '@expensify/react-native-live-markdown'; import type {ForwardedRef} from 'react'; -import React, {useCallback, useMemo, useRef} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef} from 'react'; import type {NativeSyntheticEvent, TextInput, TextInputChangeEventData, TextInputPasteEventData} from 'react-native'; import {StyleSheet} from 'react-native'; import type {FileObject} from '@components/AttachmentModal'; import type {AnimatedMarkdownTextInputRef} from '@components/RNMarkdownTextInput'; import RNMarkdownTextInput from '@components/RNMarkdownTextInput'; +import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useMarkdownStyle from '@hooks/useMarkdownStyle'; import useResetComposerFocus from '@hooks/useResetComposerFocus'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -46,6 +47,15 @@ function Composer( const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const {inputCallbackRef, inputRef: autoFocusInputRef} = useAutoFocusInput(); + + useEffect(() => { + if (autoFocus === !!autoFocusInputRef.current) { + return; + } + inputCallbackRef(autoFocus ? textInput.current : null); + }, [autoFocus, inputCallbackRef, autoFocusInputRef]); + /** * Set the TextInput Ref * @param {Element} el @@ -57,6 +67,10 @@ function Composer( return; } + if (autoFocus) { + inputCallbackRef(el); + } + // This callback prop is used by the parent component using the constructor to // get a ref to the inner textInput element e.g. if we do // this.textInput = el} /> this will not diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index 306319f061ca..7a4512ad5aea 100755 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -4,7 +4,7 @@ import type {BaseSyntheticEvent, ForwardedRef} from 'react'; import React, {useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {flushSync} from 'react-dom'; // eslint-disable-next-line no-restricted-imports -import type {DimensionValue, NativeSyntheticEvent, Text as RNText, TextInput, TextInputKeyPressEventData, TextInputSelectionChangeEventData, TextStyle} from 'react-native'; +import type {NativeSyntheticEvent, Text as RNText, TextInput, TextInputKeyPressEventData, TextInputSelectionChangeEventData, ViewStyle} from 'react-native'; import {DeviceEventEmitter, StyleSheet, View} from 'react-native'; import type {AnimatedMarkdownTextInputRef} from '@components/RNMarkdownTextInput'; import RNMarkdownTextInput from '@components/RNMarkdownTextInput'; @@ -19,6 +19,7 @@ import * as Browser from '@libs/Browser'; import updateIsFullComposerAvailable from '@libs/ComposerUtils/updateIsFullComposerAvailable'; import * as EmojiUtils from '@libs/EmojiUtils'; import * as FileUtils from '@libs/fileDownload/FileUtils'; +import focusComposerWithDelay from '@libs/focusComposerWithDelay'; import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition'; import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager'; import CONST from '@src/CONST'; @@ -100,7 +101,7 @@ function Composer( }); const [caretContent, setCaretContent] = useState(''); const [valueBeforeCaret, setValueBeforeCaret] = useState(''); - const [textInputWidth, setTextInputWidth] = useState(''); + const [textInputWidth, setTextInputWidth] = useState(''); const [isRendered, setIsRendered] = useState(false); const isScrollBarVisible = useIsScrollBarVisible(textInput, value ?? ''); const [prevScroll, setPrevScroll] = useState(); @@ -291,7 +292,7 @@ function Composer( return; } - const currentText = textInput.current.innerText; + const currentText = textInput.current.value; textInput.current.clear(); // We need to reset the selection to 0,0 manually after clearing the text input on web @@ -352,7 +353,7 @@ function Composer( opacity: 0, }} > - + {`${valueBeforeCaret} `} ({horizontal: 0, vertical: 0}); - const threeDotsMenuContainerRef = useRef(null); - const connectionOptions = [ - { - icon: Expensicons.LinkCopy, - text: translate('workspace.common.createNewConnection'), - onSelected: () => { - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID)); - setIsReuseConnectionsPopoverOpen(false); - }, - }, - { - icon: Expensicons.Copy, - text: translate('workspace.common.reuseExistingConnection'), - onSelected: () => { - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_EXISTING_CONNECTIONS.getRoute(policyID)); - setIsReuseConnectionsPopoverOpen(false); - }, - }, - ]; - - return ( - <> -