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
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,8 @@ const CONST = {
},

XERO_CONFIG: {
AUTO_SYNC: 'autoSync',
SYNC: 'sync',
IMPORT_CUSTOMERS: 'importCustomers',
IMPORT_TAX_RATES: 'importTaxRates',
},
Expand Down
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/accounting/xero/import/taxes',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/import/taxes` as const,
},
POLICY_ACCOUNTING_XERO_ADVANCED: {
route: 'settings/workspaces/:policyID/accounting/xero/advanced',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/xero/advanced` 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 @@ -238,6 +238,7 @@ const SCREENS = {
XERO_ORGANIZATION: 'Policy_Accounting_Xero_Customers',
XERO_CUSTOMER: 'Policy_Acounting_Xero_Import_Customer',
XERO_TAXES: 'Policy_Accounting_Xero_Taxes',
XERO_ADVANCED: 'Policy_Accounting_Xero_Advanced',
},
INITIAL: 'Workspace_Initial',
PROFILE: 'Workspace_Profile',
Expand Down
6 changes: 5 additions & 1 deletion src/components/ConnectionLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ function ConnectionLayout({displayName, headerTitle, children, title, subtitle,
onBackButtonPress={() => Navigation.goBack()}
/>
<ScrollView contentContainerStyle={[styles.pb2, styles.ph5]}>
<View style={[styles.pb2]}>{title && <Text style={styles.pb5}>{translate(title)}</Text>}</View>
{title && (
<View style={[styles.pb2]}>
<Text style={styles.pb5}>{translate(title)}</Text>
</View>
)}
{subtitle && <Text style={styles.textLabelSupporting}>{translate(subtitle)}</Text>}
{children}
</ScrollView>
Expand Down
10 changes: 10 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2003,6 +2003,16 @@ export default {
customersDescription: 'Import customer contacts. Billable expenses need tags for export. Expenses will carry the customer information to Xero for sales invoices.',
taxesDescription: 'Choose whether to import tax rates and tax defaults from your accounting integration.',
notImported: 'Not imported',
advancedConfig: {
advanced: 'Advanced',
autoSync: 'Auto-Sync',
autoSyncDescription: 'Sync Xero and Expensify automatically every day.',
purchaseBillStatusTitle: 'Set purchase bill status (optional)',
reimbursedReports: 'Sync reimbursed reports',
reimbursedReportsDescription: 'Any time a report is paid using Expensify ACH, the corresponding bill payment will be created in the Xero account below.',
xeroBillPaymentAccount: 'Xero Bill Payment Account',
xeroInvoiceCollectionAccount: 'Xero Invoice Collections Account',
},
},
type: {
free: 'Free',
Expand Down
11 changes: 11 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2036,6 +2036,17 @@ export default {
'Importar contactos de clientes. Los gastos facturables necesitan etiquetas para la exportación. Los gastos llevarán la información del cliente a Xero para las facturas de ventas.',
taxesDescription: 'Elige si quires importar las tasas de impuestos y los impuestos por defecto de tu integración de contaduría.',
notImported: 'No importado',
advancedConfig: {
advanced: 'Avanzado',
autoSync: 'Autosincronización',
autoSyncDescription: 'Sincroniza Xero y Expensify automáticamente todos los días.',
purchaseBillStatusTitle: 'Set purchase bill status (optional)',
reimbursedReports: 'Sincronizar informes reembolsados',
reimbursedReportsDescription:
'Cada vez que se pague un informe utilizando Expensify ACH, se creará el correspondiente pago de la factura en la cuenta de Xero indicadas a continuación.',
xeroBillPaymentAccount: 'Cuenta de pago de las facturas de Xero',
xeroInvoiceCollectionAccount: 'Cuenta de cobro de las facturas Xero',
},
},
type: {
free: 'Gratis',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: () => require('../../../../pages/workspace/accounting/xero/XeroOrganizationConfigurationPage').default as React.ComponentType,
[SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER]: () => require('../../../../pages/workspace/accounting/xero/import/XeroCustomerConfigurationPage').default as React.ComponentType,
[SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES]: () => require('../../../../pages/workspace/accounting/xero/XeroTaxesConfigurationPage').default as React.ComponentType,
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: () => require('../../../../pages/workspace/accounting/xero/advanced/XeroAdvancedPage').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 @@ -43,6 +43,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION,
SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER,
SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES,
SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED,
],
[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 @@ -328,6 +328,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION]: {path: ROUTES.POLICY_ACCOUNTING_XERO_ORGANIZATION.route},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER]: {path: ROUTES.POLICY_ACCOUNTING_XERO_CUSTOMER.route},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES]: {path: ROUTES.POLICY_ACCOUNTING_XERO_TAXES.route},
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: {path: ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.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 @@ -321,6 +321,9 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES]: {
policyID: string;
};
[SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED]: {
policyID: string;
};
[SCREENS.GET_ASSISTANCE]: {
backTo: Routes;
};
Expand Down
5 changes: 5 additions & 0 deletions src/libs/actions/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,10 @@ function clearQBOErrorField(policyID: string, fieldName: string) {
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {quickbooksOnline: {config: {errorFields: {[fieldName]: null}}}}});
}

function clearXeroErrorField(policyID: string, fieldName: string) {
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {connections: {xero: {config: {errorFields: {[fieldName]: null}}}}});
}

function setWorkspaceReimbursement(policyID: string, reimbursementChoice: ValueOf<typeof CONST.POLICY.REIMBURSEMENT_CHOICES>, reimburserEmail: string) {
const policy = getPolicy(policyID);

Expand Down Expand Up @@ -5148,6 +5152,7 @@ export {
renamePolicyTag,
clearPolicyTagErrors,
clearQBOErrorField,
clearXeroErrorField,
clearWorkspaceReimbursementErrors,
deleteWorkspaceCategories,
deletePolicyTags,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/accounting/PolicyAccountingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function accountingIntegrationData(
),
onImportPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_IMPORT.getRoute(policyID)),
onExportPagePress: () => {},
onAdvancedPagePress: () => {},
onAdvancedPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID)),
};
default:
return undefined;
Expand Down
104 changes: 104 additions & 0 deletions src/pages/workspace/accounting/xero/advanced/XeroAdvancedPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react';
import ConnectionLayout from '@components/ConnectionLayout';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Connections from '@libs/actions/connections';
import * as ErrorUtils from '@libs/ErrorUtils';
import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
import withPolicyConnections from '@pages/workspace/withPolicyConnections';
import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
import * as Policy from '@userActions/Policy';
import CONST from '@src/CONST';

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

const policyID = policy?.id ?? '';
const xeroConfig = policy?.connections?.xero?.config;
const {autoSync, pendingFields, sync} = xeroConfig ?? {};
const xeroData = policy?.connections?.xero?.data;

return (
<ConnectionLayout
displayName={XeroAdvancedPage.displayName}
headerTitle="workspace.xero.advancedConfig.advanced"
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
policyID={policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED}
>
<ToggleSettingOptionRow
key={translate('workspace.xero.advancedConfig.autoSync')}
title={translate('workspace.xero.advancedConfig.autoSync')}
subtitle={translate('workspace.xero.advancedConfig.autoSyncDescription')}
shouldPlaceSubtitleBelowSwitch
wrapperStyle={styles.mv3}
isActive={Boolean(autoSync?.enabled)}
onToggle={() =>
Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.AUTO_SYNC, {
enabled: !autoSync?.enabled,
})
}
pendingAction={pendingFields?.autoSync}
errors={ErrorUtils.getLatestErrorField(xeroConfig ?? {}, CONST.XERO_CONFIG.AUTO_SYNC)}
onCloseError={() => Policy.clearXeroErrorField(policyID, CONST.XERO_CONFIG.AUTO_SYNC)}
/>
<OfflineWithFeedback pendingAction={pendingFields?.export}>
<MenuItemWithTopDescription
shouldShowRightIcon
title={xeroConfig?.export.billStatus.purchase}
description={translate('workspace.xero.advancedConfig.purchaseBillStatusTitle')}
key={translate('workspace.xero.advancedConfig.purchaseBillStatusTitle')}
wrapperStyle={[styles.sectionMenuItemTopDescription]}
onPress={() => {}}
/>
</OfflineWithFeedback>
<ToggleSettingOptionRow
key={translate('workspace.xero.advancedConfig.reimbursedReports')}
title={translate('workspace.xero.advancedConfig.reimbursedReports')}
subtitle={translate('workspace.xero.advancedConfig.reimbursedReportsDescription')}
shouldPlaceSubtitleBelowSwitch
wrapperStyle={styles.mv3}
isActive={Boolean(sync?.syncReimbursedReports)}
onToggle={() =>
Connections.updatePolicyConnectionConfig(policyID, CONST.POLICY.CONNECTIONS.NAME.XERO, CONST.XERO_CONFIG.SYNC, {
syncReimbursedReports: !sync?.syncReimbursedReports,
})
}
pendingAction={pendingFields?.sync}
errors={ErrorUtils.getLatestErrorField(xeroConfig ?? {}, CONST.XERO_CONFIG.SYNC)}
onCloseError={() => Policy.clearXeroErrorField(policyID, CONST.XERO_CONFIG.SYNC)}
/>
{sync?.syncReimbursedReports && (
<>
<OfflineWithFeedback pendingAction={pendingFields?.sync}>
<MenuItemWithTopDescription
shouldShowRightIcon
title={String(xeroData?.bankAccounts)}
description={translate('workspace.xero.advancedConfig.xeroBillPaymentAccount')}
key={translate('workspace.xero.advancedConfig.xeroBillPaymentAccount')}
wrapperStyle={[styles.sectionMenuItemTopDescription]}
onPress={() => {}}
/>
</OfflineWithFeedback>
<OfflineWithFeedback pendingAction={pendingFields?.sync}>
<MenuItemWithTopDescription
shouldShowRightIcon
title={String(xeroData?.bankAccounts)}
description={translate('workspace.xero.advancedConfig.xeroInvoiceCollectionAccount')}
key={translate('workspace.xero.advancedConfig.xeroInvoiceCollectionAccount')}
wrapperStyle={[styles.sectionMenuItemTopDescription]}
onPress={() => {}}
/>
</OfflineWithFeedback>
</>
)}
</ConnectionLayout>
);
}

XeroAdvancedPage.displayName = 'XeroAdvancedPage';

export default withPolicyConnections(XeroAdvancedPage);