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

[QBD] Handle the syncing for QBD #50500

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
12 changes: 12 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2366,6 +2366,7 @@ const CONST = {
SYNC_STAGE_NAME: {
STARTING_IMPORT_QBO: 'startingImportQBO',
STARTING_IMPORT_XERO: 'startingImportXero',
STARTING_IMPORT_QBD: 'startingImportQBD',
QBO_IMPORT_MAIN: 'quickbooksOnlineImportMain',
QBO_IMPORT_CUSTOMERS: 'quickbooksOnlineImportCustomers',
QBO_IMPORT_EMPLOYEES: 'quickbooksOnlineImportEmployees',
Expand All @@ -2382,6 +2383,17 @@ const CONST = {
QBO_SYNC_APPLY_CUSTOMERS: 'quickbooksOnlineSyncApplyCustomers',
QBO_SYNC_APPLY_PEOPLE: 'quickbooksOnlineSyncApplyEmployees',
QBO_SYNC_APPLY_CLASSES_LOCATIONS: 'quickbooksOnlineSyncApplyClassesLocations',
QBD_IMPORT_TITLE: 'quickbooksDesktopImportTitle',
QBD_IMPORT_ACCOUNTS: 'quickbooksDesktopImportAccounts',
QBD_IMPORT_APPROVE_CERTIFICATE: 'quickbooksDesktopImportApproveCertificate',
QBD_IMPORT_DIMENSIONS: 'quickbooksDesktopImportDimensions',
QBD_IMPORT_CLASSES: 'quickbooksDesktopImportClasses',
QBD_IMPORT_CUSTOMERS: 'quickbooksDesktopImportCustomers',
QBD_IMPORT_VENDORS: 'quickbooksDesktopImportVendors',
QBD_IMPORT_EMPLOYEES: 'quickbooksDesktopImportEmployees',
QBD_IMPORT_MORE: 'quickbooksDesktopImportMore',
QBD_IMPORT_GENERIC: 'quickbooksDesktopImportSavePolicy',
QBD_WEB_CONNECTOR_REMINDER: 'quickbooksDesktopWebConnectorReminder',
JOB_DONE: 'jobDone',
XERO_SYNC_STEP: 'xeroSyncStep',
XERO_SYNC_XERO_REIMBURSED_REPORTS: 'xeroSyncXeroReimbursedReports',
Expand Down
19 changes: 19 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3558,6 +3558,7 @@ const translations = {
other: 'Other integrations',
syncNow: 'Sync now',
disconnect: 'Disconnect',
reinstall: 'Reinstall connector',
disconnectTitle: ({connectionName}: OptionalParam<ConnectionNameParams> = {}) => {
const integrationName =
connectionName && CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName] ? CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName] : 'integration';
Expand Down Expand Up @@ -3606,14 +3607,18 @@ const translations = {
syncStageName: ({stage}: SyncStageNameConnectionsParams) => {
switch (stage) {
case 'quickbooksOnlineImportCustomers':
case 'quickbooksDesktopImportCustomers':
return 'Importing customers';
case 'quickbooksOnlineImportEmployees':
case 'netSuiteSyncImportEmployees':
case 'intacctImportEmployees':
case 'quickbooksDesktopImportEmployees':
return 'Importing employees';
case 'quickbooksOnlineImportAccounts':
case 'quickbooksDesktopImportAccounts':
return 'Importing accounts';
case 'quickbooksOnlineImportClasses':
case 'quickbooksDesktopImportClasses':
return 'Importing classes';
case 'quickbooksOnlineImportLocations':
return 'Importing locations';
Expand All @@ -3632,6 +3637,19 @@ const translations = {
return 'Importing Xero data';
case 'startingImportQBO':
return 'Importing QuickBooks Online data';
case 'startingImportQBD':
case 'quickbooksDesktopImportMore':
return 'Importing QuickBooks Desktop data';
case 'quickbooksDesktopImportTitle':
return 'Importing title';
case 'quickbooksDesktopImportApproveCertificate':
return 'Importing approve ceritificate';
case 'quickbooksDesktopImportDimensions':
return 'Importing dimensions';
case 'quickbooksDesktopImportSavePolicy':
return 'Importing save policy';
case 'quickbooksDesktopWebConnectorReminder':
return 'Still syncing data with QuickBooks... Please make sure the Web Connector is running';
case 'quickbooksOnlineSyncTitle':
return 'Syncing QuickBooks Online data';
case 'quickbooksOnlineSyncLoadData':
Expand Down Expand Up @@ -3705,6 +3723,7 @@ const translations = {
case 'netSuiteSyncImportSubsidiaries':
return 'Importing subsidiaries';
case 'netSuiteSyncImportVendors':
case 'quickbooksDesktopImportVendors':
return 'Importing vendors';
case 'intacctCheckConnection':
return 'Checking Sage Intacct connection';
Expand Down
19 changes: 19 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3565,6 +3565,7 @@ const translations = {
other: 'Otras integraciones',
syncNow: 'Sincronizar ahora',
disconnect: 'Desconectar',
reinstall: 'Reinstalar el conector',
disconnectTitle: ({connectionName}: OptionalParam<ConnectionNameParams> = {}) => {
const integrationName =
connectionName && CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName] ? CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionName] : 'integración';
Expand Down Expand Up @@ -3612,14 +3613,18 @@ const translations = {
syncStageName: ({stage}: SyncStageNameConnectionsParams) => {
switch (stage) {
case 'quickbooksOnlineImportCustomers':
case 'quickbooksDesktopImportCustomers':
return 'Importando clientes';
case 'quickbooksOnlineImportEmployees':
case 'netSuiteSyncImportEmployees':
case 'intacctImportEmployees':
case 'quickbooksDesktopImportEmployees':
return 'Importando empleados';
case 'quickbooksOnlineImportAccounts':
case 'quickbooksDesktopImportAccounts':
return 'Importando cuentas';
case 'quickbooksOnlineImportClasses':
case 'quickbooksDesktopImportClasses':
return 'Importando clases';
case 'quickbooksOnlineImportLocations':
return 'Importando localidades';
Expand All @@ -3638,6 +3643,19 @@ const translations = {
return 'Importando datos desde Xero';
case 'startingImportQBO':
return 'Importando datos desde QuickBooks Online';
case 'startingImportQBD':
case 'quickbooksDesktopImportMore':
return 'Importando datos desde QuickBooks Desktop';
case 'quickbooksDesktopImportTitle':
return 'Importando título';
case 'quickbooksDesktopImportApproveCertificate':
return 'Importando certificado de aprobación';
case 'quickbooksDesktopImportDimensions':
return 'Importando dimensiones';
case 'quickbooksDesktopImportSavePolicy':
return 'Importando política de guardado';
case 'quickbooksDesktopWebConnectorReminder':
return 'Aún sincronizando datos con QuickBooks... Por favor, asegúrate de que el Conector Web esté en funcionamiento';
case 'quickbooksOnlineSyncTitle':
return 'Sincronizando datos desde QuickBooks Online';
case 'quickbooksOnlineSyncLoadData':
Expand Down Expand Up @@ -3705,6 +3723,7 @@ const translations = {
case 'netSuiteSyncImportSubsidiaries':
return 'Importando subsidiarias';
case 'netSuiteSyncImportVendors':
case 'quickbooksDesktopImportVendors':
return 'Importando proveedores';
case 'netSuiteSyncExpensifyReimbursedReports':
return 'Marcando facturas y recibos de NetSuite como pagados';
Expand Down
7 changes: 7 additions & 0 deletions src/libs/API/parameters/SyncConnectionParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type SyncConnectionParams = {
policyID: string;
idempotencyKey: string;
forceDataRefresh?: boolean;
};

export default SyncConnectionParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,4 +334,5 @@ export type {default as SetCompanyCardExportAccountParams} from './SetCompanyCar
export type {default as SetMissingPersonalDetailsAndShipExpensifyCardParams} from './SetMissingPersonalDetailsAndShipExpensifyCardParams';
export type {default as SetInvoicingTransferBankAccountParams} from './SetInvoicingTransferBankAccountParams';
export type {default as ConnectPolicyToQuickBooksDesktopParams} from './ConnectPolicyToQuickBooksDesktopParams';
export type {default as SyncConnectionParams} from './SyncConnectionParams';
export type {default as UpdateQuickbooksDesktopExpensesExportDestinationTypeParams} from './UpdateQuickbooksDesktopExpensesExportDestinationTypeParams';
1 change: 1 addition & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,7 @@ const READ_COMMANDS = {
SYNC_POLICY_TO_XERO: 'SyncPolicyToXero',
SYNC_POLICY_TO_NETSUITE: 'SyncPolicyToNetSuite',
SYNC_POLICY_TO_SAGE_INTACCT: 'SyncPolicyToSageIntacct',
SYNC_POLICY_TO_QUICKBOOKS_DESKTOP: 'SyncPolicyToQuickbooksDesktop',
OPEN_REIMBURSEMENT_ACCOUNT_PAGE: 'OpenReimbursementAccountPage',
OPEN_WORKSPACE_VIEW: 'OpenWorkspaceView',
GET_MAPBOX_ACCESS_TOKEN: 'GetMapboxAccessToken',
Expand Down
32 changes: 19 additions & 13 deletions src/libs/actions/connections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import isObject from 'lodash/isObject';
import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import * as API from '@libs/API';
import type {RemovePolicyConnectionParams, UpdateManyPolicyConnectionConfigurationsParams, UpdatePolicyConnectionConfigParams} from '@libs/API/parameters';
import type {RemovePolicyConnectionParams, SyncConnectionParams, UpdateManyPolicyConnectionConfigurationsParams, UpdatePolicyConnectionConfigParams} from '@libs/API/parameters';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import * as ErrorUtils from '@libs/ErrorUtils';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -163,6 +163,9 @@ function getSyncConnectionParameters(connectionName: PolicyConnectionName) {
case CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT: {
return {readCommand: READ_COMMANDS.SYNC_POLICY_TO_SAGE_INTACCT, stageInProgress: CONST.POLICY.CONNECTIONS.SYNC_STAGE_NAME.SAGE_INTACCT_SYNC_CHECK_CONNECTION};
}
case CONST.POLICY.CONNECTIONS.NAME.QBD: {
return {readCommand: READ_COMMANDS.SYNC_POLICY_TO_QUICKBOOKS_DESKTOP, stageInProgress: CONST.POLICY.CONNECTIONS.SYNC_STAGE_NAME.STARTING_IMPORT_QBD};
}
default:
return undefined;
}
Expand All @@ -173,8 +176,9 @@ function getSyncConnectionParameters(connectionName: PolicyConnectionName) {
*
* @param policyID - ID of the policy for which the sync is needed
* @param connectionName - Name of the connection, QBO/Xero
* @param forceDataRefresh - If true, it will trigger a full data refresh
*/
function syncConnection(policyID: string, connectionName: PolicyConnectionName | undefined) {
function syncConnection(policyID: string, connectionName: PolicyConnectionName | undefined, forceDataRefresh = false) {
if (!connectionName) {
return;
}
Expand Down Expand Up @@ -203,17 +207,19 @@ function syncConnection(policyID: string, connectionName: PolicyConnectionName |
},
];

API.read(
syncConnectionData.readCommand,
{
policyID,
idempotencyKey: policyID,
},
{
optimisticData,
failureData,
},
);
const parameters: SyncConnectionParams = {
policyID,
idempotencyKey: policyID,
};

if (connectionName === CONST.POLICY.CONNECTIONS.NAME.QBD) {
parameters.forceDataRefresh = forceDataRefresh;
}

API.read(syncConnectionData.readCommand, parameters, {
optimisticData,
failureData,
});
}

function updateManyPolicyConnectionConfigs<TConnectionName extends ConnectionNameExceptNetSuite, TConfigUpdate extends Partial<Connections[TConnectionName]['config']>>(
Expand Down
28 changes: 23 additions & 5 deletions src/pages/workspace/accounting/PolicyAccountingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,14 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) {

const tenants = useMemo(() => getXeroTenants(policy), [policy]);
const currentXeroOrganization = findCurrentXeroOrganization(tenants, policy?.connections?.xero?.config?.tenantID);
const shouldShowSynchronizationError = !!synchronizationError;
const shouldShowEnterCredentialsMenuItem =
shouldShowEnterCredentials && (connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT || connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.NETSUITE);
const shouldShowReinstallConnectorMenuItem = shouldShowSynchronizationError && connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.QBD;

const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo(
() => [
...(shouldShowEnterCredentials && (connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT || connectedIntegration === CONST.POLICY.CONNECTIONS.NAME.NETSUITE)
...(shouldShowEnterCredentialsMenuItem
? [
{
icon: Expensicons.Key,
Expand All @@ -118,22 +122,36 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) {
iconRight: Expensicons.NewWindow,
},
]
: [
: []),
...(shouldShowReinstallConnectorMenuItem
? [
{
icon: Expensicons.CircularArrowBackwards,
text: translate('workspace.accounting.reinstall'),
onSelected: () => startIntegrationFlow({name: CONST.POLICY.CONNECTIONS.NAME.QBD}),
shouldCallAfterModalHide: true,
iconRight: Expensicons.NewWindow,
},
]
: []),
...(!shouldShowEnterCredentialsMenuItem && !shouldShowReinstallConnectorMenuItem
? [
{
icon: Expensicons.Sync,
text: translate('workspace.accounting.syncNow'),
onSelected: () => syncConnection(policyID, connectedIntegration),
disabled: isOffline,
},
]),
]
: []),
{
icon: Expensicons.Trashcan,
text: translate('workspace.accounting.disconnect'),
onSelected: () => setIsDisconnectModalOpen(true),
shouldCallAfterModalHide: true,
},
],
[shouldShowEnterCredentials, translate, isOffline, policyID, connectedIntegration, startIntegrationFlow],
[shouldShowEnterCredentialsMenuItem, shouldShowReinstallConnectorMenuItem, translate, isOffline, policyID, connectedIntegration, startIntegrationFlow],
);

useFocusEffect(
Expand Down Expand Up @@ -269,7 +287,6 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) {
if (!connectedIntegration) {
return [];
}
const shouldShowSynchronizationError = !!synchronizationError;
const shouldHideConfigurationOptions = isConnectionUnverified(policy, connectedIntegration);
const integrationData = getAccountingIntegrationData(connectedIntegration, policyID, translate, policy, undefined, undefined, undefined, canUseNetSuiteUSATax);
const iconProps = integrationData?.icon ? {icon: integrationData.icon, iconType: CONST.ICON_TYPE_AVATAR} : {};
Expand Down Expand Up @@ -364,6 +381,7 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) {
isSyncInProgress,
connectedIntegration,
synchronizationError,
shouldShowSynchronizationError,
policyID,
translate,
styles.sectionMenuItemTopDescription,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import React from 'react';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import type {StackScreenProps} from '@react-navigation/stack';
import {useEffect} from 'react';
import {useOnyx} from 'react-native-onyx';
import {isConnectionInProgress, syncConnection} from '@libs/actions/connections';
import Navigation from '@libs/Navigation/Navigation';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';

function QuickBooksDesktopSetupFlowSyncPage() {
// TODO: [QBD] will be implemented in https://github.com/Expensify/App/issues/49698
return <FullScreenLoadingIndicator />;
type QuickBooksDesktopSetupFlowSyncPageProps = StackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL>;

function QuickBooksDesktopSetupFlowSyncPage({route}: QuickBooksDesktopSetupFlowSyncPageProps) {
const policyID: string = route.params.policyID;
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID ?? '-1'}`);
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID ?? '-1'}`);

useEffect(() => {
if (!policyID) {
return;
}

const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy);
if (!isSyncInProgress) {
syncConnection(policyID, CONST.POLICY.CONNECTIONS.NAME.QBD, true);
}

Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING.getRoute(policyID));

// disabling this rule, as we want this to run only on the first render
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, []);

return null;
}

QuickBooksDesktopSetupFlowSyncPage.displayName = 'QuickBooksDesktopSetupFlowSyncPage';
Expand Down
Loading