Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3796,6 +3796,15 @@ const CONST = {
DEFAULT_MAX_EXPENSE_AMOUNT: 200000,
DEFAULT_MAX_AMOUNT_NO_RECEIPT: 2500,
DEFAULT_MAX_AMOUNT_NO_ITEMIZED_RECEIPT: 7500,
DEFAULT_PROHIBITED_EXPENSES: {
alcohol: false,
hotelIncidentals: false,
gambling: true,
tobacco: false,
adultEntertainment: true,
},
Comment on lines +3799 to +3805

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this used @WojtekBoman

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM on these defaults. Note, this is only set on paid workspaces

            'alcohol' => false,
            'hotelIncidentals' => false,
            'adultEntertainment' => true,
            'gambling' => true,
            'tobacco' => false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the billable and reimbursable too 👍

DEFAULT_BILLABLE: false,
DEFAULT_REIMBURSABLE: true,
DEFAULT_TAG_LIST: {
Tag: {
name: 'Tag',
Expand Down
1 change: 1 addition & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Erste Schritte',
createWorkspace: 'Workspace erstellen',
connectAccounting: ({integrationName}: {integrationName: string}) => `Mit ${integrationName} verbinden`,
connectAccountingDefault: 'Mit Buchhaltung verbinden',
customizeCategories: 'Buchhaltungskategorien anpassen',
linkCompanyCards: 'Firmenkarten verknüpfen',
setupRules: 'Ausgabelimits einrichten',
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,7 @@ const translations = {
title: 'Getting started',
createWorkspace: 'Create a workspace',
connectAccounting: ({integrationName}: {integrationName: string}) => `Connect to ${integrationName}`,
connectAccountingDefault: 'Connect to accounting',
customizeCategories: 'Customize accounting categories',
linkCompanyCards: 'Link company cards',
setupRules: 'Set up spend rules',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Primeros pasos',
createWorkspace: 'Crear un espacio de trabajo',
connectAccounting: ({integrationName}: {integrationName: string}) => `Conectar con ${integrationName}`,
connectAccountingDefault: 'Conectar a contabilidad',
customizeCategories: 'Personalizar categorías contables',
linkCompanyCards: 'Vincular tarjetas corporativas',
setupRules: 'Configurar reglas de gasto',
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Premiers pas',
createWorkspace: 'Créer un espace de travail',
connectAccounting: ({integrationName}: {integrationName: string}) => `Se connecter à ${integrationName}`,
connectAccountingDefault: 'Connecter à la comptabilité',
customizeCategories: 'Personnaliser les catégories comptables',
linkCompanyCards: 'Lier des cartes d’entreprise',
setupRules: 'Configurer les règles de dépense',
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Per iniziare',
createWorkspace: 'Crea uno spazio di lavoro',
connectAccounting: ({integrationName}: {integrationName: string}) => `Connetti a ${integrationName}`,
connectAccountingDefault: 'Connetti alla contabilità',
customizeCategories: 'Personalizza le categorie contabili',
linkCompanyCards: 'Collega carte aziendali',
setupRules: 'Configura le regole di spesa',
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'はじめに',
createWorkspace: 'ワークスペースを作成',
connectAccounting: ({integrationName}: {integrationName: string}) => `${integrationName}に接続する`,
connectAccountingDefault: '会計ソフトに接続',
customizeCategories: '会計カテゴリをカスタマイズする',
linkCompanyCards: '会社カードを連携',
setupRules: '支出ルールを設定',
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Aan de slag',
createWorkspace: 'Maak een werkruimte',
connectAccounting: ({integrationName}: {integrationName: string}) => `Verbind met ${integrationName}`,
connectAccountingDefault: 'Verbind met boekhouding',
customizeCategories: 'Boekhoudcategorieën aanpassen',
linkCompanyCards: 'Bedrijfspassen koppelen',
setupRules: 'Uitgavenregels instellen',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Pierwsze kroki',
createWorkspace: 'Utwórz przestrzeń roboczą',
connectAccounting: ({integrationName}: {integrationName: string}) => `Połącz z ${integrationName}`,
connectAccountingDefault: 'Połącz z księgowością',
customizeCategories: 'Dostosuj kategorie księgowe',
linkCompanyCards: 'Połącz firmowe karty',
setupRules: 'Skonfiguruj zasady wydatków',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Introdução',
createWorkspace: 'Criar um workspace',
connectAccounting: ({integrationName}: {integrationName: string}) => `Conectar ao ${integrationName}`,
connectAccountingDefault: 'Conectar à contabilidade',
customizeCategories: 'Personalizar categorias contábeis',
linkCompanyCards: 'Vincular cartões corporativos',
setupRules: 'Configurar regras de gasto',
Expand Down
1 change: 1 addition & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,7 @@ const translations: TranslationDeepObject<typeof en> = {
title: '入门',
createWorkspace: '创建工作区',
connectAccounting: ({integrationName}: {integrationName: string}) => `连接到 ${integrationName}`,
connectAccountingDefault: '连接会计系统',
customizeCategories: '自定义会计类别',
linkCompanyCards: '关联公司卡',
setupRules: '设置消费规则',
Expand Down
66 changes: 57 additions & 9 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

let allPolicies: OnyxCollection<Policy>;

Onyx.connect({

Check warning on line 79 in src/libs/PolicyUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
waitForCollectionCallback: true,
callback: (value) => (allPolicies = value),
Expand Down Expand Up @@ -692,22 +692,70 @@
}

/**
* Checks if a policy has any non-default rules configured.
* Defaults are: no approval/expense/coding rules and no custom rules text.
* Checks if a policy has any rules configured (structured rules, individual expense limits, or prohibited expenses).
*/
function hasNonDefaultRules(policy: OnyxEntry<Policy>): boolean {
function hasConfiguredRules(policy: OnyxEntry<Policy>): boolean {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add tests for this util

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have tests for this util?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rewrite this method to do early returns - everytime we find that any of these values is non-default, we can return true early

+1 lets add robust tests for this one, should be easy

if (!policy) {
return false;
}

const hasCustomRules = !!policy.customRules && policy.customRules.trim().length > 0;
if (!!policy.customRules && policy.customRules.trim().length > 0) {
return true;
}

const {rules} = policy;
const hasApprovalRules = !!rules?.approvalRules && rules.approvalRules.length > 0;
const hasExpenseRules = !!rules?.expenseRules && rules.expenseRules.length > 0;
const hasCodingRules = !!rules?.codingRules && Object.keys(rules.codingRules).length > 0;
if (!!rules?.approvalRules && rules.approvalRules.length > 0) {
return true;
}
if (!!rules?.expenseRules && rules.expenseRules.length > 0) {
return true;
}
if (!!rules?.codingRules && Object.keys(rules.codingRules).length > 0) {
return true;
}

if (!!policy.maxExpenseAmount && policy.maxExpenseAmount !== CONST.DISABLED_MAX_EXPENSE_VALUE && policy.maxExpenseAmount !== CONST.POLICY.DEFAULT_MAX_EXPENSE_AMOUNT) {
return true;
}
if (!!policy.maxExpenseAge && policy.maxExpenseAge !== CONST.DISABLED_MAX_EXPENSE_VALUE && policy.maxExpenseAge !== CONST.POLICY.DEFAULT_MAX_EXPENSE_AGE) {
return true;
}
if (
!!policy.maxExpenseAmountNoReceipt &&
policy.maxExpenseAmountNoReceipt !== CONST.DISABLED_MAX_EXPENSE_VALUE &&
policy.maxExpenseAmountNoReceipt !== CONST.POLICY.DEFAULT_MAX_AMOUNT_NO_RECEIPT
) {
return true;
}
if (
!!policy.maxExpenseAmountNoItemizedReceipt &&
policy.maxExpenseAmountNoItemizedReceipt !== CONST.DISABLED_MAX_EXPENSE_VALUE &&
policy.maxExpenseAmountNoItemizedReceipt !== CONST.POLICY.DEFAULT_MAX_AMOUNT_NO_ITEMIZED_RECEIPT
) {
return true;
}

if (policy.defaultBillable) {
return true;
}
if (policy.defaultReimbursable === false) {
return true;
}
if (policy.eReceipts) {
return true;
}
if (policy.requireCompanyCardsEnabled) {
return true;
}

return hasCustomRules || hasApprovalRules || hasExpenseRules || hasCodingRules;
const {prohibitedExpenses} = policy;
return (
!!prohibitedExpenses &&
Object.entries(CONST.POLICY.DEFAULT_PROHIBITED_EXPENSES).some(([key, defaultValue]) => {
const value = prohibitedExpenses[key as keyof typeof CONST.POLICY.DEFAULT_PROHIBITED_EXPENSES];
return value !== undefined && value !== defaultValue;
})
);
}

/**
Expand Down Expand Up @@ -2132,7 +2180,7 @@
getTagLists,
hasTags,
hasCustomCategories,
hasNonDefaultRules,
hasConfiguredRules,
getTaxByID,
getUnitRateValue,
getRateDisplayValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@ import useCardFeeds from '@hooks/useCardFeeds';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import {enablePolicyCategories} from '@libs/actions/Policy/Category';
import {hasCompanyCardFeeds} from '@libs/CardUtils';
import Navigation from '@libs/Navigation/Navigation';
import {hasAccountingConnections, hasCustomCategories, hasNonDefaultRules, isPaidGroupPolicy, isPendingDeletePolicy, isPolicyAdmin} from '@libs/PolicyUtils';
import {
getValidConnectedIntegration,
hasAccountingFeatureConnection,
hasConfiguredRules,
hasCustomCategories,
isPaidGroupPolicy,
isPendingDeletePolicy,
isPolicyAdmin,
} from '@libs/PolicyUtils';
import isWithinGettingStartedPeriod from '@pages/home/GettingStartedSection/utils/isWithinGettingStartedPeriod';
import {enablePolicyCategories} from '@userActions/Policy/Category';
import {enableCompanyCards, enablePolicyConnections, enablePolicyRules} from '@userActions/Policy/Policy';
import {enableCompanyCards, enablePolicyConnections} from '@userActions/Policy/Policy';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';

type GettingStartedItem = {
key: string;
Expand Down Expand Up @@ -46,6 +54,7 @@ function useGettingStartedItems(): UseGettingStartedItemsResult {
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`);
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${activePolicyID}`);
const [allCardFeeds] = useCardFeeds(activePolicyID);
const isAccountingEnabled = !!policy?.areConnectionsEnabled || hasAccountingFeatureConnection(policy);

const emptyResult: UseGettingStartedItemsResult = {shouldShowSection: false, items: []};

Expand Down Expand Up @@ -77,12 +86,14 @@ function useGettingStartedItems(): UseGettingStartedItemsResult {

const isDirectConnect = !!reportedIntegration && DIRECT_CONNECT_INTEGRATIONS.has(reportedIntegration);

if (isDirectConnect) {
const integrationName = CONST.ONBOARDING_ACCOUNTING_MAPPING[reportedIntegration as keyof typeof CONST.ONBOARDING_ACCOUNTING_MAPPING] ?? String(reportedIntegration);
if (isAccountingEnabled) {
const integrationName = isDirectConnect
? (CONST.ONBOARDING_ACCOUNTING_MAPPING[reportedIntegration as keyof typeof CONST.ONBOARDING_ACCOUNTING_MAPPING] ?? String(reportedIntegration))
: undefined;
items.push({
key: 'connectAccounting',
label: translate('homePage.gettingStartedSection.connectAccounting', {integrationName}),
isComplete: hasAccountingConnections(policy),
label: integrationName ? translate('homePage.gettingStartedSection.connectAccounting', {integrationName}) : translate('homePage.gettingStartedSection.connectAccountingDefault'),
isComplete: !!getValidConnectedIntegration(policy) || Object.values(policy?.connections ?? {}).some((conn) => !!conn?.lastSync?.successfulDate),
route: ROUTES.WORKSPACE_ACCOUNTING.getRoute(activePolicyID),
isFeatureEnabled: policy.areConnectionsEnabled,
enableFeature: () => enablePolicyConnections(activePolicyID, true, false),
Expand Down Expand Up @@ -111,10 +122,8 @@ function useGettingStartedItems(): UseGettingStartedItemsResult {
items.push({
key: 'setupRules',
label: translate('homePage.gettingStartedSection.setupRules'),
isComplete: hasNonDefaultRules(policy),
isComplete: hasConfiguredRules(policy),
route: ROUTES.WORKSPACE_RULES.getRoute(activePolicyID),
isFeatureEnabled: policy.areRulesEnabled,
enableFeature: () => enablePolicyRules(policy, true, false),
});
}

Expand Down
Loading
Loading