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

Xero Import main page and Xero Organization Page #40984

Merged
8 changes: 8 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,14 @@ const ROUTES = {
route: 'r/:reportID/transaction/:transactionID/receipt',
getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const,
},
POLICY_ACCOUNTING_XERO_IMPORT: {
route: 'settings/workspaces/:policyID/accounting/xero/import',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import` as const,
},
POLICY_ACCOUNTING_XERO_ORGANIZATION: {
route: 'settings/workspaces/:policyID/accounting/xero/organization/:currentOrganizationID',
getRoute: (policyID: string, currentOrganizationID: string) => `settings/workspaces/${policyID}/accounting/xero/organization/${currentOrganizationID}` 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
2 changes: 2 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ const SCREENS = {
QUICKBOOKS_ONLINE_ADVANCED: 'Policy_Accounting_Quickbooks_Online_Advanced',
QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR: 'Policy_Accounting_Quickbooks_Online_Account_Selector',
QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR: 'Policy_Accounting_Quickbooks_Online_Invoice_Account_Selector',
XERO_IMPORT: 'Policy_Accounting_Xero_Import',
XERO_ORGANIZATION: 'Policy_Accounting_Xero_Customers',
},
INITIAL: 'Workspace_Initial',
PROFILE: 'Workspace_Profile',
Expand Down
16 changes: 11 additions & 5 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1882,17 +1882,12 @@ export default {
`You have been invited to ${workspaceName || 'a workspace'}! Download the Expensify mobile app at use.expensify.com/download to start tracking your expenses.`,
},
qbo: {
import: 'Import',
importDescription: 'Choose which coding configurations are imported from QuickBooks Online to Expensify.',
classes: 'Classes',
accounts: 'Chart of accounts',
locations: 'Locations',
taxes: 'Taxes',
customers: 'Customers/Projects',
imported: 'Imported',
displayedAs: 'Displayed as',
notImported: 'Not imported',
importedAsTags: 'Imported, displayed as tags',
importedAsReportFields: 'Imported, displayed as report fields',
accountsDescription: 'Chart of Accounts import as categories when connected to an accounting integration, this cannot be disabled.',
accountsSwitchTitle: 'Enable newly imported Chart of Accounts.',
Expand Down Expand Up @@ -1992,6 +1987,13 @@ export default {
'If you are exporting invoices from Expensify to Quickbooks Online, this is the account the invoice will appear against once marked as paid.',
},
},
xero: {
organization: 'Xero organization',
organizationDescription: 'Select the organization in Xero you are importing data from.',
importDescription: 'Choose which coding configurations are imported from Xero to Expensify.',
trackingCategories: 'Tracking categories',
customers: 'Re-bill customers',
},
type: {
free: 'Free',
control: 'Control',
Expand Down Expand Up @@ -2220,6 +2222,10 @@ export default {
}
}
},
accounts: 'Chart of accounts',
taxes: 'Taxes',
imported: 'Imported',
importedAsTags: 'Imported, displayed as tags',
disconnectPrompt: (integrationToConnect?: ConnectionName, currentIntegration?: ConnectionName): string => {
switch (integrationToConnect) {
case CONST.POLICY.CONNECTIONS.NAME.QBO:
Expand Down
16 changes: 11 additions & 5 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1906,17 +1906,12 @@ export default {
`¡Has sido invitado a ${workspaceName}! Descargue la aplicación móvil Expensify en use.expensify.com/download para comenzar a rastrear sus gastos.`,
},
qbo: {
import: 'Importación',
importDescription: 'Elige que configuraciónes de codificación son importadas desde QuickBooks Online a Expensify.',
classes: 'Clases',
accounts: 'Plan de cuentas',
locations: 'Lugares',
taxes: 'Impuestos',
customers: 'Clientes/Proyectos',
imported: 'Importado',
displayedAs: 'Mostrado como',
notImported: 'No importado',
importedAsTags: 'Importado, mostrado como etiqueta',
importedAsReportFields: 'Importado, mostrado como campo de informe',
accountsDescription: 'Los planes de cuentas se importan como categorías cuando está conectado con una integración de contaduría, esto no se puede desactivar.',
accountsSwitchTitle: 'Habilita el plan de cuentas recien importado',
Expand Down Expand Up @@ -2019,6 +2014,13 @@ export default {
'Si está exportando facturas de Expensify a Quickbooks Online, ésta es la cuenta en la que aparecerá la factura una vez marcada como pagada.',
},
},
xero: {
organization: 'Organización Xero',
organizationDescription: 'Seleccione la organización en Xero desde la que está importando los datos.',
importDescription: 'Elija qué configuraciones de codificación se importan de Xero a Expensify.',
trackingCategories: 'Categorías de seguimiento',
customers: 'Volver a facturar a los clientes',
},
type: {
free: 'Gratis',
control: 'Control',
Expand Down Expand Up @@ -2215,6 +2217,10 @@ export default {
}
}
},
accounts: 'Plan de cuentas',
taxes: 'Impuestos',
imported: 'Importado',
importedAsTags: 'Importado, mostrado como etiqueta',
disconnectPrompt: (integrationToConnect?: ConnectionName, currentIntegration?: ConnectionName): string => {
switch (integrationToConnect) {
case CONST.POLICY.CONNECTIONS.NAME.QBO:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,9 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
require('../../../../pages/workspace/accounting/qbo/advanced/QuickbooksAccountSelectPage').default as React.ComponentType,
[SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR]: () =>
require('../../../../pages/workspace/accounting/qbo/advanced/QuickbooksInvoiceAccountSelectPage').default as React.ComponentType,

[SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT]: () => require('../../../../pages/workspace/accounting/xero/XeroImportPage').default as React.ComponentType,
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: () => require('../../../../pages/workspace/accounting/xero/XeroOrganizationConfigurationPage').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 @@ -39,6 +39,8 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ADVANCED,
SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR,
SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR,
SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT,
SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION,
],
[SCREENS.WORKSPACE.TAXES]: [
SCREENS.WORKSPACE.TAXES_SETTINGS,
Expand Down
2 changes: 2 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR]: {
path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR.route,
},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT]: {path: ROUTES.POLICY_ACCOUNTING_XERO_IMPORT.route},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: {path: ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.route},
[SCREENS.WORKSPACE.DESCRIPTION]: {
path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route,
},
Expand Down
7 changes: 7 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,13 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER]: {
policyID: string;
};
[SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT]: {
policyID: string;
};
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: {
policyID: string;
organizationID: string;
};
[SCREENS.GET_ASSISTANCE]: {
backTo: Routes;
};
Expand Down
5 changes: 3 additions & 2 deletions src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import type SCREENS from '@src/SCREENS';
import type {PendingAction} from '@src/types/onyx/OnyxCommon';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type IconAsset from '@src/types/utils/IconAsset';
import AccessOrNotFoundWrapper from './AccessOrNotFoundWrapper';
import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscreenLoading';
Expand Down Expand Up @@ -47,8 +48,8 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
const {isSmallScreenWidth} = useWindowDimensions();
const {translate} = useLocalize();
const {canUseAccountingIntegrations} = usePermissions();
const hasAccountingConnection = !!policy?.areConnectionsEnabled && !!policy?.connections;
const isSyncTaxEnabled = !!policy?.connections?.quickbooksOnline?.config?.syncTax;
const hasAccountingConnection = !!policy?.areConnectionsEnabled && !isEmptyObject(policy?.connections);
const isSyncTaxEnabled = !!policy?.connections?.quickbooksOnline?.config.syncTax || !!policy?.connections?.xero?.config.importTaxRates;

const spendItems: Item[] = [
{
Expand Down
37 changes: 35 additions & 2 deletions src/pages/workspace/accounting/PolicyAccountingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Policy, PolicyConnectionSyncProgress} from '@src/types/onyx';
import type {PolicyConnectionName} from '@src/types/onyx/Policy';
import type {PolicyConnectionName, Tenant} from '@src/types/onyx/Policy';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type IconAsset from '@src/types/utils/IconAsset';

Expand Down Expand Up @@ -91,7 +91,7 @@ function accountingIntegrationData(
integrationToDisconnect={integrationToDisconnect}
/>
),
onImportPagePress: () => {},
onImportPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_IMPORT.getRoute(policyID)),
onExportPagePress: () => {},
onAdvancedPagePress: () => {},
};
Expand All @@ -114,6 +114,18 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting
const connectedIntegration = accountingIntegrations.find((integration) => !!policy?.connections?.[integration]) ?? connectionSyncProgress?.connectionName;
const policyID = policy?.id ?? '';

const policyConnectedToXero = connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.XERO;

const tenants = useMemo<Tenant[]>(() => {

This comment was marked as outdated.

// Due to the way optional chain is being handled in this useMemo we are forced to use this approach to properly handle undefined values
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (!policy || !policy.connections || !policy.connections.xero || !policy.connections.xero.data) {
return [];
}
return policy?.connections?.xero?.data?.tenants ?? [];
}, [policy]);
const currentXeroOrganization = tenants.find((tenant) => tenant.id === policy?.connections?.xero.config.tenantID);

const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo(
() => [
{
Expand Down Expand Up @@ -185,6 +197,24 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting
</View>
),
},
...(policyConnectedToXero
? [
{
description: translate('workspace.xero.organization'),
iconRight: Expensicons.ArrowRight,
title: currentXeroOrganization?.name,
wrapperStyle: [styles.sectionMenuItemTopDescription],
shouldShowRightIcon: tenants.length > 1,
shouldShowDescriptionOnTop: true,
onPress: () => {
if (!(tenants.length > 1)) {
return;
}
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.getRoute(policyID, currentXeroOrganization?.id ?? ''));
},
},
]
: []),
...(isEmptyObject(policy?.connections)
? []
: [
Expand Down Expand Up @@ -217,9 +247,12 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting
}, [
connectedIntegration,
connectionSyncProgress?.stageInProgress,
currentXeroOrganization,
tenants,
isSyncInProgress,
overflowMenu,
policy?.connections,
policyConnectedToXero,
policyID,
styles,
theme.spinner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) {
shouldEnableMaxHeight
testID={QuickbooksChartOfAccountsPage.displayName}
>
<HeaderWithBackButton title={translate('workspace.qbo.accounts')} />
<HeaderWithBackButton title={translate('workspace.accounting.accounts')} />
<ScrollView contentContainerStyle={[styles.pb2, styles.ph5]}>
<Text style={styles.pb5}>{translate('workspace.qbo.accountsDescription')}</Text>
<View style={[styles.flexRow, styles.mb2, styles.alignItemsCenter, styles.justifyContentBetween]}>
Expand All @@ -43,7 +43,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) {
<OfflineWithFeedback pendingAction={pendingFields?.enableNewCategories}>
<View style={[styles.flex1, styles.alignItemsEnd, styles.pl3]}>
<Switch
accessibilityLabel={translate('workspace.qbo.accounts')}
accessibilityLabel={translate('workspace.accounting.accounts')}
isOn={isSwitchOn}
onToggle={() =>
Connections.updatePolicyConnectionConfig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) {
<Text style={styles.pb5}>{translate('workspace.qbo.classesDescription')}</Text>
<View style={[styles.flexRow, styles.mb4, styles.alignItemsCenter, styles.justifyContentBetween]}>
<View style={styles.flex1}>
<Text fontSize={variables.fontSizeNormal}>{translate('workspace.qbo.import')}</Text>
<Text fontSize={variables.fontSizeNormal}>{translate('workspace.accounting.import')}</Text>
</View>
<OfflineWithFeedback pendingAction={pendingFields?.syncClasses}>
<View style={[styles.flex1, styles.alignItemsEnd, styles.pl3]}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) {
<Text style={styles.pb5}>{translate('workspace.qbo.customersDescription')}</Text>
<View style={[styles.flexRow, styles.mb4, styles.alignItemsCenter, styles.justifyContentBetween]}>
<View style={styles.flex1}>
<Text fontSize={variables.fontSizeNormal}>{translate('workspace.qbo.import')}</Text>
<Text fontSize={variables.fontSizeNormal}>{translate('workspace.accounting.import')}</Text>
</View>
<OfflineWithFeedback pendingAction={pendingFields?.syncCustomers}>
<View style={[styles.flex1, styles.alignItemsEnd, styles.pl3]}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ function QuickbooksImportPage({policy}: WithPolicyProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const quickbooksOnlineConfigTitles = {
[CONST.INTEGRATION_ENTITY_MAP_TYPES.DEFAULT]: translate('workspace.qbo.imported'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED]: translate('workspace.qbo.imported'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.DEFAULT]: translate('workspace.accounting.imported'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED]: translate('workspace.accounting.imported'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.NOT_IMPORTED]: translate('workspace.qbo.notImported'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE]: translate('workspace.qbo.notImported'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG]: translate('workspace.qbo.importedAsTags'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG]: translate('workspace.accounting.importedAsTags'),
[CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD]: translate('workspace.qbo.importedAsReportFields'),
};
const policyID = policy?.id ?? '';
const {syncClasses, syncCustomers, syncLocations, syncTaxes, enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {};

const sections = [
{
description: translate('workspace.qbo.accounts'),
description: translate('workspace.accounting.accounts'),
action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)),
hasError: Boolean(policy?.errors?.enableNewCategories),
title: enableNewCategories,
Expand Down Expand Up @@ -61,7 +61,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) {

if (policy?.connections?.quickbooksOnline.data.country !== CONST.COUNTRY.US) {
sections.push({
description: translate('workspace.qbo.taxes'),
description: translate('workspace.accounting.taxes'),
action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_TAXES.getRoute(policyID)),
hasError: Boolean(policy?.errors?.syncTaxes),
title: syncTaxes,
Expand All @@ -80,7 +80,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) {
shouldEnableMaxHeight
testID={QuickbooksImportPage.displayName}
>
<HeaderWithBackButton title={translate('workspace.qbo.import')} />
<HeaderWithBackButton title={translate('workspace.accounting.import')} />
<ScrollView contentContainerStyle={styles.pb2}>
<Text style={[styles.ph5, styles.pb5]}>{translate('workspace.qbo.importDescription')}</Text>
{sections.map((section) => (
Expand Down
Loading
Loading