Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wave Collect][Xero][Advanced] Bill Payment Account Selector #41690

4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/accounting/xero/advanced/invoice-account-selector',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced/invoice-account-selector` as const,
},
POLICY_ACCOUNTING_XERO_BILL_PAYMENT_ACCOUNT_SELECTOR: {
route: 'settings/workspaces/:policyID/accounting/xero/advanced/bill-payment-account-selector',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced/bill-payment-account-selector` as const,
},
POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_IMPORT: {
route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import` as const,
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ const SCREENS = {
XERO_EXPORT: 'Policy_Accounting_Xero_Export',
XERO_ADVANCED: 'Policy_Accounting_Xero_Advanced',
XERO_INVOICE_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Invoice_Account_Selector',
XERO_BILL_PAYMENT_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Bill_Payment_Account_Selector',
},
INITIAL: 'Workspace_Initial',
PROFILE: 'Workspace_Profile',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2051,6 +2051,8 @@ export default {
xeroBillPaymentAccount: 'Xero Bill Payment Account',
xeroInvoiceCollectionAccount: 'Xero Invoice Collections Account',
invoiceAccountSelectorDescription: "As you've enabled exporting invoices from Expensify to Xero, this is the account the invoice will appear against once marked as paid.",
xeroBillPaymentAccountDescription:
"As you've enabled sync reimbursed reports, you will need to select the bank account your reimbursements are coming out of, and we'll create the payment in Xero.",
},
},
type: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2086,6 +2086,8 @@ export default {
xeroInvoiceCollectionAccount: 'Cuenta de cobro de las facturas Xero',
invoiceAccountSelectorDescription:
'Como ha activado la exportación de facturas de Expensify a Xero, esta es la cuenta en la que aparecerá la factura una vez marcada como pagada.',
xeroBillPaymentAccountDescription:
'Como has activado la sincronización de los informes reembolsados, tendrás que seleccionar la cuenta bancaria de la que se producen estos reembolsos y crearemos el pago en Xero.',
},
},
type: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: () => require('../../../../pages/workspace/accounting/xero/advanced/XeroAdvancedPage').default as React.ComponentType,
[SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR]: () =>
require('../../../../pages/workspace/accounting/xero/advanced/XeroInvoiceAccountSelectorPage').default as React.ComponentType,
[SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR]: () =>
require('../../../../pages/workspace/accounting/xero/advanced/XeroBillPaymentAccountSelectorPage').default as React.ComponentType,
[SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage').default as React.ComponentType,
[SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET]: () =>
require('../../../../pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage').default as React.ComponentType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT,
SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED,
SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR,
SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR,
],
[SCREENS.WORKSPACE.TAXES]: [
SCREENS.WORKSPACE.TAXES_SETTINGS,
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT]: {path: ROUTES.POLICY_ACCOUNTING_XERO_EXPORT.route},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: {path: ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.route},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR]: {path: ROUTES.POLICY_ACCOUNTING_XERO_INVOICE_SELECTOR.route},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR]: {path: ROUTES.POLICY_ACCOUNTING_XERO_BILL_PAYMENT_ACCOUNT_SELECTOR.route},
[SCREENS.WORKSPACE.DESCRIPTION]: {
path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route,
},
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR]: {
policyID: string;
};
[SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR]: {
policyID: string;
};
[SCREENS.GET_ASSISTANCE]: {
backTo: Routes;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) {
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN]}
policyID={policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED}
contentContainerStyle={[styles.pb2, styles.ph5]}
>
<View style={[styles.flexRow, styles.mb4, styles.alignItemsCenter, styles.justifyContentBetween]}>
<View style={styles.flex1}>
Expand Down
19 changes: 12 additions & 7 deletions src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,18 @@ function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) {
const xeroConfig = policy?.connections?.xero?.config;
const {autoSync, pendingFields, sync} = xeroConfig ?? {};
const {bankAccounts} = policy?.connections?.xero?.data ?? {};
const {invoiceCollectionsAccountID} = sync ?? {};
const {invoiceCollectionsAccountID, reimbursementAccountID} = sync ?? {};

const selectedBankAccountName = useMemo(() => {
const selectedAccount = (bankAccounts ?? []).find((bank) => bank.id === invoiceCollectionsAccountID);
const getSelectedAccountName = useMemo(
() => (accountId: string) => {
const selectedAccount = (bankAccounts ?? []).find((bank) => bank.id === accountId);
return selectedAccount?.name ?? '';
},
[bankAccounts],
);

return selectedAccount?.name ?? '';
}, [bankAccounts, invoiceCollectionsAccountID]);
const selectedBankAccountName = getSelectedAccountName(invoiceCollectionsAccountID ?? '');
const selectedBillPaymentAccountName = getSelectedAccountName(reimbursementAccountID ?? '');

return (
<ConnectionLayout
Expand Down Expand Up @@ -86,11 +91,11 @@ function XeroAdvancedPage({policy}: WithPolicyConnectionsProps) {
<OfflineWithFeedback pendingAction={pendingFields?.sync}>
<MenuItemWithTopDescription
shouldShowRightIcon
title={String(bankAccounts)}
title={String(selectedBillPaymentAccountName)}
description={translate('workspace.xero.advancedConfig.xeroBillPaymentAccount')}
key={translate('workspace.xero.advancedConfig.xeroBillPaymentAccount')}
wrapperStyle={[styles.sectionMenuItemTopDescription]}
onPress={() => {}}
onPress={() => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_BILL_PAYMENT_ACCOUNT_SELECTOR.getRoute(policyID))}
/>
</OfflineWithFeedback>
<OfflineWithFeedback pendingAction={pendingFields?.sync}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, {useCallback, useMemo} from 'react';
import {View} from 'react-native';
import RadioListItem from '@components/SelectionList/RadioListItem';
import type {SelectorType} from '@components/SelectionScreen';
import SelectionScreen from '@components/SelectionScreen';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Connections from '@libs/actions/connections';
import Navigation from '@libs/Navigation/Navigation';
import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
import withPolicyConnections from '@pages/workspace/withPolicyConnections';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';

function XeroBillPaymentAccountSelectorPage({policy}: WithPolicyConnectionsProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();

const policyID = policy?.id ?? '';
const {bankAccounts} = policy?.connections?.xero?.data ?? {};

const {reimbursementAccountID, syncReimbursedReports} = policy?.connections?.xero?.config.sync ?? {};

const xeroSelectorOptions = useMemo<SelectorType[]>(
() =>
(bankAccounts ?? []).map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: reimbursementAccountID === id,
})),
[reimbursementAccountID, bankAccounts],
);

const listHeaderComponent = useMemo(
() => (
<View style={[styles.pb2, styles.ph5]}>
<Text style={[styles.pb5, styles.textNormal]}>{translate('workspace.xero.advancedConfig.xeroBillPaymentAccountDescription')}</Text>
</View>
),
[translate, styles.pb2, styles.ph5, styles.pb5, styles.textNormal],
);

const initiallyFocusedOptionKey = useMemo(() => xeroSelectorOptions?.find((mode) => mode.isSelected)?.keyForList, [xeroSelectorOptions]);

const updateMode = useCallback(
({value}: SelectorType) => {
Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.SYNC, {
reimbursementAccountID: value,
});
Navigation.goBack(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID));
},
[policyID],
);

return (
<SelectionScreen
policyID={policyID}
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
featureName={CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED}
displayName={XeroBillPaymentAccountSelectorPage.displayName}
sections={[{data: xeroSelectorOptions}]}
listItem={RadioListItem}
shouldBeBlocked={!syncReimbursedReports}
Copy link
Contributor

Choose a reason for hiding this comment

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

NAB, we should also add more condition here to address the case when Xero is disconnected

const connectedIntegration = accountingIntegrations.find((integration) => !!policy?.connections?.[integration]) ?? connectionSyncProgress?.connectionName;
const policyConnectedToXero = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.XERO;
shouldBeBlocked={!syncReimbursedReports ||  !policyConnectedToXero}

We can do this as a follow up since we will need to update other screens as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Agreed. This is required in all the screens.

onSelectRow={updateMode}
initiallyFocusedOptionKey={initiallyFocusedOptionKey}
headerContent={listHeaderComponent}
onBackButtonPress={() => Navigation.goBack(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID))}
title="workspace.xero.advancedConfig.xeroBillPaymentAccount"
/>
);
}

XeroBillPaymentAccountSelectorPage.displayName = 'XeroBillPaymentAccountSelectorPage';

export default withPolicyConnections(XeroBillPaymentAccountSelectorPage);
Loading