diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7102d6396381..e06a2413bb4a 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -459,20 +459,20 @@ const ONYXKEYS = { /** Collection of objects where each object represents the owner of the workspace that is past due billing AND the user is a member of. */ SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END: 'sharedNVP_private_billingGracePeriodEnd_', - /** Expensify cards settings */ - SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS: 'sharedNVP_private_expensifyCardSettings_', - /** * Stores the card list for a given fundID and feed in the format: card__ * So for example: card_12345_Expensify Card */ WORKSPACE_CARDS_LIST: 'card_', + /** Expensify cards settings */ + PRIVATE_EXPENSIFY_CARD_SETTINGS: 'private_expensifyCardSettings_', + /** Stores which connection is set up to use Continuous Reconciliation */ - SHARED_NVP_EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION: 'sharedNVP_expensifyCard_continuousReconciliationConnection_', + EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION: 'expensifyCard_continuousReconciliationConnection_', /** The value that indicates whether Continuous Reconciliation should be used on the domain */ - SHARED_NVP_EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION: 'sharedNVP_expensifyCard_useContinuousReconciliation_', + EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION: 'expensifyCard_useContinuousReconciliation_', }, /** List of Form ids */ @@ -737,10 +737,10 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS]: OnyxTypes.PolicyConnectionSyncProgress; [ONYXKEYS.COLLECTION.SNAPSHOT]: OnyxTypes.SearchResults; [ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END]: OnyxTypes.BillingGraceEndPeriod; - [ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS]: OnyxTypes.ExpensifyCardSettings; + [ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS]: OnyxTypes.ExpensifyCardSettings; [ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST]: OnyxTypes.WorkspaceCardsList; - [ONYXKEYS.COLLECTION.SHARED_NVP_EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION]: OnyxTypes.PolicyConnectionName; - [ONYXKEYS.COLLECTION.SHARED_NVP_EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION]: boolean; + [ONYXKEYS.COLLECTION.EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION]: OnyxTypes.PolicyConnectionName; + [ONYXKEYS.COLLECTION.EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION]: boolean; }; type OnyxValuesMapping = { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 27f565929c56..75af6a4b1df2 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -716,12 +716,11 @@ const ROUTES = { }, WORKSPACE_ACCOUNTING_CARD_RECONCILIATION: { route: 'settings/workspaces/:policyID/accounting/:connection/card-reconciliation', - getRoute: (policyID: string, connection: ValueOf) => `settings/workspaces/${policyID}/accounting/${connection}/card-reconciliation` as const, + getRoute: (policyID: string, connection?: ConnectionName) => `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?: ValueOf) => - `settings/workspaces/${policyID}/accounting/${connection}/card-reconciliation/account` as const, + getRoute: (policyID: string, connection?: ConnectionName) => `settings/workspaces/${policyID}/accounting/${connection}/card-reconciliation/account` as const, }, WORKSPACE_CATEGORIES: { route: 'settings/workspaces/:policyID/categories', diff --git a/src/libs/API/parameters/ConfigureExpensifyCardsForPolicyParams.ts b/src/libs/API/parameters/ConfigureExpensifyCardsForPolicyParams.ts new file mode 100644 index 000000000000..dea6b2705188 --- /dev/null +++ b/src/libs/API/parameters/ConfigureExpensifyCardsForPolicyParams.ts @@ -0,0 +1,6 @@ +type ConfigureExpensifyCardsForPolicyParams = { + policyID: string; + bankAccountID: number; +}; + +export default ConfigureExpensifyCardsForPolicyParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index c89bf660fcd4..2954bfb4bc1c 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -270,3 +270,4 @@ export type {default as ExportSearchItemsToCSVParams} from './ExportSearchItemsT export type {default as UpdateExpensifyCardLimitParams} from './UpdateExpensifyCardLimitParams'; export type {CreateWorkspaceApprovalParams, UpdateWorkspaceApprovalParams, RemoveWorkspaceApprovalParams} from './WorkspaceApprovalParams'; export type {default as StartIssueNewCardFlowParams} from './StartIssueNewCardFlowParams'; +export type {default as ConfigureExpensifyCardsForPolicyParams} from './ConfigureExpensifyCardsForPolicyParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 57350bf6de13..22cc0b8ff56d 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -325,6 +325,7 @@ const WRITE_COMMANDS = { CREATE_WORKSPACE_APPROVAL: 'CreateWorkspaceApproval', UPDATE_WORKSPACE_APPROVAL: 'UpdateWorkspaceApproval', REMOVE_WORKSPACE_APPROVAL: 'RemoveWorkspaceApproval', + CONFIGURE_EXPENSIFY_CARDS_FOR_POLICY: 'ConfigureExpensifyCardsForPolicy', } as const; type WriteCommand = ValueOf; @@ -656,6 +657,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.CREATE_WORKSPACE_APPROVAL]: Parameters.CreateWorkspaceApprovalParams; [WRITE_COMMANDS.UPDATE_WORKSPACE_APPROVAL]: Parameters.UpdateWorkspaceApprovalParams; [WRITE_COMMANDS.REMOVE_WORKSPACE_APPROVAL]: Parameters.RemoveWorkspaceApprovalParams; + [WRITE_COMMANDS.CONFIGURE_EXPENSIFY_CARDS_FOR_POLICY]: Parameters.ConfigureExpensifyCardsForPolicyParams; }; const READ_COMMANDS = { diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 7468fb9a3679..9f341e623b20 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -923,6 +923,15 @@ function getCurrentTaxID(policy: OnyxEntry, taxID: string): string | und return Object.keys(policy?.taxRates?.taxes ?? {}).find((taxIDKey) => policy?.taxRates?.taxes?.[taxIDKey].previousTaxCode === taxID || taxIDKey === taxID); } +function getWorkspaceAccountID(policyID: string) { + const policy = getPolicy(policyID); + + if (!policy) { + return 0; + } + return policy.workspaceAccountID ?? 0; +} + export { canEditTaxRate, extractPolicyIDFromPath, @@ -1024,6 +1033,7 @@ export { getSubmitToEmail, getForwardsToAccount, getSubmitToAccountID, + getWorkspaceAccountID, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/libs/actions/Card.ts b/src/libs/actions/Card.ts index 205a8dc41bba..916ffd07a82a 100644 --- a/src/libs/actions/Card.ts +++ b/src/libs/actions/Card.ts @@ -206,14 +206,14 @@ function revealVirtualCardDetails(cardID: number): Promise }); } -function updateSettlementFrequency(policyID: string, frequency: ValueOf) { +function updateSettlementFrequency(workspaceAccountID: number, frequency: ValueOf) { // TODO: remove this code when the API is ready if (frequency === CONST.EXPENSIFY_CARD.FREQUENCY_SETTING.DAILY) { - Onyx.merge(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS}${policyID}`, { + Onyx.merge(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${workspaceAccountID}`, { monthlySettlementDate: null, }); } else { - Onyx.merge(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS}${policyID}`, { + Onyx.merge(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${workspaceAccountID}`, { monthlySettlementDate: new Date(), }); } @@ -222,7 +222,7 @@ function updateSettlementFrequency(policyID: string, frequency: ValueOf bankAccountList?.[paymentBankAccountID], [paymentBankAccountID, bankAccountList]); + const selectedBankAccount = useMemo(() => bankAccountList?.[paymentBankAccountID.toString()], [paymentBankAccountID, bankAccountList]); + const bankAccountNumber = useMemo(() => selectedBankAccount?.accountData?.accountNumber ?? '', [selectedBankAccount]); + const settlementAccountEnding = getLastFourDigits(bankAccountNumber); const sections = useMemo(() => { const data = Object.values(bankAccountList ?? {}).map((bankAccount) => ({ diff --git a/src/pages/workspace/expensifyCard/WorkspaceCardListHeader.tsx b/src/pages/workspace/expensifyCard/WorkspaceCardListHeader.tsx index 0ec5b2fc18fa..cff89628db6e 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceCardListHeader.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceCardListHeader.tsx @@ -22,7 +22,7 @@ function WorkspaceCardListHeader() { const isLessThanMediumScreen = isMediumScreenWidth || isSmallScreenWidth; // TODO: uncomment the code line below to use cardSettings data from Onyx when it's supported - // const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS}${policyID}`); + // const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${workspaceAccountID}`); const cardSettings = mockedSettings; return ( diff --git a/src/pages/workspace/expensifyCard/WorkspaceCardSettingsPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceCardSettingsPage.tsx index 399ff41d945b..4e295c66060a 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceCardSettingsPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceCardSettingsPage.tsx @@ -11,6 +11,7 @@ import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {getLastFourDigits} from '@libs/BankAccountUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; import type {SettingsNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -25,17 +26,18 @@ function WorkspaceCardSettingsPage({route}: WorkspaceCardSettingsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const policyID = route.params?.policyID; + const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyID); const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST); - const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS}${policyID}`); + const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${workspaceAccountID}`); - const paymentBankAccountID = cardSettings?.paymentBankAccountID ?? ''; + const paymentBankAccountID = cardSettings?.paymentBankAccountID ?? 0; // const isMonthlySettlementAllowed = cardSettings?.isMonthlySettlementAllowed ?? true; const settlementFrequency = cardSettings?.monthlySettlementDate ? CONST.EXPENSIFY_CARD.FREQUENCY_SETTING.MONTHLY : CONST.EXPENSIFY_CARD.FREQUENCY_SETTING.DAILY; // TODO: replace this line with the following line and uncomment the previous comment const isSettlementFrequencyBlocked = settlementFrequency === CONST.EXPENSIFY_CARD.FREQUENCY_SETTING.DAILY; // const isSettlementFrequencyBlocked = !isMonthlySettlementAllowed && settlementFrequency === CONST.EXPENSIFY_CARD.FREQUENCY_SETTING.DAILY; - const bankAccountNumber = bankAccountList?.[paymentBankAccountID]?.accountData?.accountNumber ?? ''; + const bankAccountNumber = bankAccountList?.[paymentBankAccountID.toString()]?.accountData?.accountNumber ?? ''; return ( { setIsConfirmModalVisible(false); - Card.updateExpensifyCardLimit(policyID, Number(cardID), Number(newLimit) * 100, card.nameValuePairs?.limit); + Card.updateExpensifyCardLimit(workspaceAccountID, Number(cardID), Number(newLimit) * 100, card.nameValuePairs?.limit); Navigation.goBack(); }; diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx index 470b2c683e70..b96d86d06582 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx @@ -31,12 +31,11 @@ function WorkspaceExpensifyCardBankAccounts({route}: WorkspaceExpensifyCardBankA const policyID = route?.params?.policyID ?? '-1'; const handleAddBankAccount = () => { - // TODO: call to API - UpdateCardSettlementAccount Navigation.navigate(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute('new', policyID, ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID))); }; - const handleSelectBankAccount = (value: number) => { - Card.updateSettlementAccount(policyID, value); + const handleSelectBankAccount = (value?: number) => { + Card.configureExpensifyCardsForPolicy(policyID, value); Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID)); }; @@ -45,14 +44,12 @@ function WorkspaceExpensifyCardBankAccounts({route}: WorkspaceExpensifyCardBankA return null; } - // const eligibleBankAccounts = Object.values(bankAccountsList).filter((bankAccount) => bankAccount.accountData.allowDebit || bankAccount.accountData.type === CONST.BANK_ACCOUNT.TYPE.BUSINESS); const eligibleBankAccounts = CardUtils.getEligibleBankAccountsForCard(bankAccountsList); return eligibleBankAccounts.map((bankAccount) => { const bankName = (bankAccount.accountData?.addressName ?? '') as BankName; const bankAccountNumber = bankAccount.accountData?.accountNumber ?? ''; - // TODO: change 1 to 0 - applied for testing purposes, as sometimes accountData lacks fundID - const bankAccountID = bankAccount.accountData?.fundID ?? 1; + const bankAccountID = bankAccount.accountData?.bankAccountID; const {icon, iconSize, iconStyles} = getBankIcon({bankName, styles}); diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx index 86ac9ba496b7..156889273aa9 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx @@ -2,6 +2,7 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; import {useOnyx} from 'react-native-onyx'; import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -13,8 +14,9 @@ type WorkspaceExpensifyCardPageProps = StackScreenProps { - if (isEmptyObject(bankAccountList) || isSetupUnfinished) { + if (!eligibleBankAccounts.length || isSetupUnfinished) { Navigation.navigate(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute('', policy?.id, ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policy?.id ?? '-1'))); } else { Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_BANK_ACCOUNT.getRoute(policy?.id ?? '-1')); } - }, [isSetupUnfinished, bankAccountList, policy?.id]); + }, [eligibleBankAccounts.length, isSetupUnfinished, policy?.id]); return ( { - Card.updateSettlementAccount(policyID, value); + Card.updateSettlementAccount(workspaceAccountID, value); Navigation.goBack(); }; diff --git a/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx index 2d6b9bcfad58..8e837c5a8456 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx @@ -9,6 +9,7 @@ import RadioListItem from '@components/SelectionList/RadioListItem'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; import type {SettingsNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -24,8 +25,9 @@ function WorkspaceSettlementFrequencyPage({route}: WorkspaceSettlementFrequencyP const styles = useThemeStyles(); const {translate} = useLocalize(); const policyID = route.params?.policyID ?? '-1'; + const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyID); - const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS}${policyID}`); + const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${workspaceAccountID}`); // TODO: change true for false after API is ready - true is for testing purposes const shouldShowMonthlyOption = cardSettings?.isMonthlySettlementAllowed ?? true; @@ -54,7 +56,7 @@ function WorkspaceSettlementFrequencyPage({route}: WorkspaceSettlementFrequencyP }, [translate, shouldShowMonthlyOption, selectedFrequency]); const updateSettlementFrequency = (value: ValueOf) => { - Card.updateSettlementFrequency(policyID, value); + Card.updateSettlementFrequency(workspaceAccountID, value); }; return ( diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 9724229361ec..3471e563cd4b 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1539,6 +1539,9 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Whether GL codes are enabled */ glCodes?: boolean; + + /** Workspace account ID configured for Expensify Card */ + workspaceAccountID?: number; } & Partial, 'generalSettings' | 'addWorkspaceRoom' | keyof ACHAccount >;