Skip to content

Commit

Permalink
Merge pull request Expensify#46511 from software-mansion-labs/@zfurta…
Browse files Browse the repository at this point in the history
…k/qbo-error-messages

Offline and errors pattern in Quickbooks Online integration
  • Loading branch information
deetergp authored Sep 5, 2024
2 parents 5af9f2d + 5e556ff commit fd16fdd
Show file tree
Hide file tree
Showing 36 changed files with 982 additions and 1,023 deletions.
8 changes: 6 additions & 2 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1362,21 +1362,25 @@ const CONST = {
},
QUICKBOOKS_ONLINE: 'quickbooksOnline',

QUICK_BOOKS_CONFIG: {
SYNC_CLASSES: 'syncClasses',
QUICKBOOKS_CONFIG: {
ENABLE_NEW_CATEGORIES: 'enableNewCategories',
SYNC_CLASSES: 'syncClasses',
SYNC_CUSTOMERS: 'syncCustomers',
SYNC_LOCATIONS: 'syncLocations',
SYNC_TAX: 'syncTax',
EXPORT: 'export',
EXPORTER: 'exporter',
EXPORT_DATE: 'exportDate',
NON_REIMBURSABLE_EXPENSES_ACCOUNT: 'nonReimbursableExpensesAccount',
NON_REIMBURSABLE_EXPENSES_EXPORT_DESTINATION: 'nonReimbursableExpensesExportDestination',
REIMBURSABLE_EXPENSES_ACCOUNT: 'reimbursableExpensesAccount',
REIMBURSABLE_EXPENSES_EXPORT_DESTINATION: 'reimbursableExpensesExportDestination',
NON_REIMBURSABLE_BILL_DEFAULT_VENDOR: 'nonReimbursableBillDefaultVendor',
NON_REIMBURSABLE_EXPENSE_EXPORT_DESTINATION: 'nonReimbursableExpensesExportDestination',
NON_REIMBURSABLE_EXPENSE_ACCOUNT: 'nonReimbursableExpensesAccount',
RECEIVABLE_ACCOUNT: 'receivableAccount',
AUTO_SYNC: 'autoSync',
ENABLED: 'enabled',
SYNC_PEOPLE: 'syncPeople',
AUTO_CREATE_VENDOR: 'autoCreateVendor',
REIMBURSEMENT_ACCOUNT_ID: 'reimbursementAccountID',
Expand Down
1 change: 1 addition & 0 deletions src/components/SelectionScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ function SelectionScreen<T = string>({
pendingAction={pendingAction}
style={[styles.flex1]}
contentContainerStyle={[styles.flex1]}
shouldDisableOpacity={!sections.length}
>
<SelectionList
onSelectRow={onSelectRow}
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2279,6 +2279,7 @@ export default {
accountsPayable: 'Accounts payable',
accountsPayableDescription: 'Choose where to create vendor bills.',
bankAccount: 'Bank account',
notConfigured: 'Not configured',
bankAccountDescription: 'Choose where to send checks from.',
creditCardAccount: 'Credit card account',
companyCardsLocationEnabledDescription:
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2305,6 +2305,7 @@ export default {
accountsPayable: 'Cuentas por pagar',
accountsPayableDescription: 'Elige dónde crear las facturas de proveedores.',
bankAccount: 'Cuenta bancaria',
notConfigured: 'No configurado',
bankAccountDescription: 'Elige desde dónde enviar los cheques.',
creditCardAccount: 'Cuenta de la tarjeta de crédito',
companyCardsLocationEnabledDescription:
Expand Down
70 changes: 43 additions & 27 deletions src/libs/actions/connections/QuickbooksOnline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import {getCommandURL} from '@libs/ApiUtils';
import * as ErrorUtils from '@libs/ErrorUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ConnectionName, Connections, IntegrationEntityMap} from '@src/types/onyx/Policy';

type ConnectionNameExceptNetSuite = Exclude<ConnectionName, typeof CONST.POLICY.CONNECTIONS.NAME.NETSUITE>;
import type {Connections} from '@src/types/onyx/Policy';

function getQuickbooksOnlineSetupLink(policyID: string) {
const params: ConnectPolicyToAccountingIntegrationParams = {policyID};
Expand Down Expand Up @@ -92,6 +90,7 @@ function buildOnyxDataForQuickbooksConfiguration<TSettingName extends keyof Conn
policyID: string,
settingName: TSettingName,
settingValue: Partial<Connections['quickbooksOnline']['config'][TSettingName]>,
oldSettingValue?: Partial<Connections['quickbooksOnline']['config'][TSettingName]>,
) {
const optimisticData: OnyxUpdate[] = [
{
Expand Down Expand Up @@ -123,7 +122,7 @@ function buildOnyxDataForQuickbooksConfiguration<TSettingName extends keyof Conn
connections: {
[CONST.POLICY.CONNECTIONS.NAME.QBO]: {
config: {
[settingName]: settingValue ?? null,
[settingName]: oldSettingValue ?? null,
pendingFields: {
[settingName]: null,
},
Expand Down Expand Up @@ -165,13 +164,13 @@ function buildOnyxDataForQuickbooksConfiguration<TSettingName extends keyof Conn
};
}

function updateQuickbooksOnlineEnableNewCategories(policyID: string, settingValue: boolean) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.ENABLE_NEW_CATEGORIES, settingValue);
function updateQuickbooksOnlineEnableNewCategories<TSettingValue extends Connections['quickbooksOnline']['config']['enableNewCategories']>(policyID: string, settingValue: TSettingValue) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.ENABLE_NEW_CATEGORIES, settingValue, !settingValue);

const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
policyID,
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.ENABLE_NEW_CATEGORIES),
idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.ENABLE_NEW_CATEGORIES),
};
API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_ENABLE_NEW_CATEGORIES, parameters, onyxData);
}
Expand All @@ -187,76 +186,93 @@ function updateQuickbooksOnlineAutoCreateVendor<TConfigUpdate extends Partial<Co
policyID,
autoCreateVendor: JSON.stringify(configUpdate.autoCreateVendor),
nonReimbursableBillDefaultVendor: JSON.stringify(configUpdate.nonReimbursableBillDefaultVendor),
idempotencyKey: CONST.QUICK_BOOKS_CONFIG.AUTO_CREATE_VENDOR,
idempotencyKey: CONST.QUICKBOOKS_CONFIG.AUTO_CREATE_VENDOR,
};

API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_AUTO_CREATE_VENDOR, parameters, onyxData);
}

function updateQuickbooksOnlineReimbursableExpensesAccount<TConnectionName extends ConnectionNameExceptNetSuite, TSettingName extends keyof Connections[TConnectionName]['config']>(
function updateQuickbooksOnlineReimbursableExpensesAccount<TSettingValue extends Connections['quickbooksOnline']['config']['reimbursableExpensesAccount']>(
policyID: string,
settingValue: Partial<Connections[TConnectionName]['config'][TSettingName]>,
settingValue: TSettingValue,
oldSettingValue: TSettingValue,
) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT, settingValue);
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT, settingValue, oldSettingValue);

const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
policyID,
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT),
idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.REIMBURSABLE_EXPENSES_ACCOUNT),
};
API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_REIMBURSABLE_EXPENSES_ACCOUNT, parameters, onyxData);
}

function updateQuickbooksOnlineSyncLocations(policyID: string, settingValue: IntegrationEntityMap) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_LOCATIONS, settingValue);
function updateQuickbooksOnlineSyncLocations<TSettingValue extends Connections['quickbooksOnline']['config']['syncLocations']>(
policyID: string,
settingValue: TSettingValue,
oldSettingValue?: TSettingValue,
) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_LOCATIONS, settingValue, oldSettingValue);

const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
policyID,
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_LOCATIONS),
idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_LOCATIONS),
};
API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_LOCATIONS, parameters, onyxData);
}

function updateQuickbooksOnlineSyncCustomers(policyID: string, settingValue: IntegrationEntityMap) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_CUSTOMERS, settingValue);
function updateQuickbooksOnlineSyncCustomers<TSettingValue extends Connections['quickbooksOnline']['config']['syncCustomers']>(
policyID: string,
settingValue: TSettingValue,
oldSettingValue?: TSettingValue,
) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_CUSTOMERS, settingValue, oldSettingValue);

const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
policyID,
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_CUSTOMERS),
idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_CUSTOMERS),
};
API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_CUSTOMERS, parameters, onyxData);
}

function updateQuickbooksOnlineSyncClasses(policyID: string, settingValue: IntegrationEntityMap) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_CLASSES, settingValue);
function updateQuickbooksOnlineSyncClasses<TSettingValue extends Connections['quickbooksOnline']['config']['syncClasses']>(
policyID: string,
settingValue: TSettingValue,
oldSettingValue?: TSettingValue,
) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_CLASSES, settingValue, oldSettingValue);
const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
policyID,
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_CLASSES),
idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_CLASSES),
};
API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_CLASSES, parameters, onyxData);
}

function updateQuickbooksOnlineNonReimbursableBillDefaultVendor(policyID: string, settingValue: string) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR, settingValue);
function updateQuickbooksOnlineNonReimbursableBillDefaultVendor<TSettingValue extends Connections['quickbooksOnline']['config']['nonReimbursableBillDefaultVendor']>(
policyID: string,
settingValue: TSettingValue,
oldSettingValue?: TSettingValue,
) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR, settingValue, oldSettingValue);

const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
policyID,
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR),
idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.NON_REIMBURSABLE_BILL_DEFAULT_VENDOR),
};
API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_NON_REIMBURSABLE_BILL_DEFAULT_VENDOR, parameters, onyxData);
}

function updateQuickbooksOnlineSyncTax(policyID: string, settingValue: boolean) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICK_BOOKS_CONFIG.SYNC_TAX, settingValue);
function updateQuickbooksOnlineSyncTax<TSettingValue extends Connections['quickbooksOnline']['config']['syncTax']>(policyID: string, settingValue: TSettingValue) {
const onyxData = buildOnyxDataForQuickbooksConfiguration(policyID, CONST.QUICKBOOKS_CONFIG.SYNC_TAX, settingValue, !settingValue);

const parameters: UpdateQuickbooksOnlineGenericTypeParams = {
policyID,
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(CONST.QUICK_BOOKS_CONFIG.SYNC_TAX),
idempotencyKey: String(CONST.QUICKBOOKS_CONFIG.SYNC_TAX),
};
API.write(WRITE_COMMANDS.UPDATE_QUICKBOOKS_ONLINE_SYNC_TAX, parameters, onyxData);
}
Expand Down
86 changes: 1 addition & 85 deletions src/libs/actions/connections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function createErrorFields<TConnectionName extends ConnectionNameExceptNetSuite,
}, {});
}

function updatePolicyXeroConnectionConfig<TConnectionName extends ConnectionNameExceptNetSuite, TSettingName extends keyof Connections[TConnectionName]['config']>(
function updatePolicyConnectionConfig<TConnectionName extends ConnectionNameExceptNetSuite, TSettingName extends keyof Connections[TConnectionName]['config']>(
policyID: string,
connectionName: TConnectionName,
settingName: TSettingName,
Expand Down Expand Up @@ -143,89 +143,6 @@ function updatePolicyXeroConnectionConfig<TConnectionName extends ConnectionName
};
API.write(WRITE_COMMANDS.UPDATE_POLICY_CONNECTION_CONFIG, parameters, {optimisticData, failureData, successData});
}

function updatePolicyConnectionConfig<TConnectionName extends ConnectionNameExceptNetSuite, TSettingName extends keyof Connections[TConnectionName]['config']>(
policyID: string,
connectionName: TConnectionName,
settingName: TSettingName,
settingValue: Partial<Connections[TConnectionName]['config'][TSettingName]>,
) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
connections: {
[connectionName]: {
config: {
[settingName]: settingValue ?? null,
pendingFields: {
[settingName]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
errorFields: {
[settingName]: null,
},
},
},
},
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
connections: {
[connectionName]: {
config: {
[settingName]: settingValue ?? null,
pendingFields: {
[settingName]: null,
},
errorFields: {
[settingName]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'),
},
},
},
},
},
},
];

const successData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
connections: {
[connectionName]: {
config: {
[settingName]: settingValue ?? null,
pendingFields: {
[settingName]: null,
},
errorFields: {
[settingName]: null,
},
},
},
},
},
},
];

const parameters: UpdatePolicyConnectionConfigParams = {
policyID,
connectionName,
settingName: String(settingName),
settingValue: JSON.stringify(settingValue),
idempotencyKey: String(settingName),
};
API.write(WRITE_COMMANDS.UPDATE_POLICY_CONNECTION_CONFIG, parameters, {optimisticData, failureData, successData});
}

/**
* This method returns read command and stage in progres for a given accounting integration.
*
Expand Down Expand Up @@ -465,7 +382,6 @@ function isConnectionInProgress(connectionSyncProgress: OnyxEntry<PolicyConnecti
export {
removePolicyConnection,
updatePolicyConnectionConfig,
updatePolicyXeroConnectionConfig,
updateManyPolicyConnectionConfigs,
isAuthenticationError,
syncConnection,
Expand Down
Loading

0 comments on commit fd16fdd

Please sign in to comment.