diff --git a/assets/images/product-illustrations/emptystate__records.svg b/assets/images/product-illustrations/emptystate__records.svg
new file mode 100644
index 0000000000000..e8c7c14e86c78
--- /dev/null
+++ b/assets/images/product-illustrations/emptystate__records.svg
@@ -0,0 +1,56 @@
+
+
+
diff --git a/src/CONST.ts b/src/CONST.ts
index 051ff1b71ae5e..59c448190cbc4 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -1387,7 +1387,12 @@ const CONST = {
3: 'createAccessToken',
4: 'enterCredentials',
},
- IMPORT_CUSTOM_FIELDS: ['customSegments', 'customLists'],
+ IMPORT_CUSTOM_FIELDS: {
+ CUSTOM_SEGMENTS: 'customSegments',
+ CUSTOM_LISTS: 'customLists',
+ },
+ CUSTOM_SEGMENT_FIELDS: ['segmentName', 'internalID', 'scriptID', 'mapping'],
+ CUSTOM_LIST_FIELDS: ['listName', 'internalID', 'transactionFieldID', 'mapping'],
SYNC_OPTIONS: {
SYNC_REIMBURSED_REPORTS: 'syncReimbursedReports',
SYNC_PEOPLE: 'syncPeople',
@@ -1404,6 +1409,13 @@ const CONST = {
},
},
+ NETSUITE_IMPORT: {
+ HELP_LINKS: {
+ CUSTOM_SEGMENTS: 'https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/NetSuite#custom-segments',
+ CUSTOM_LISTS: 'https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/NetSuite#custom-lists',
+ },
+ },
+
NETSUITE_EXPORT_DATE: {
LAST_EXPENSE: 'LAST_EXPENSE',
EXPORTED: 'EXPORTED',
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 906f8ef7095ea..ffd451931d975 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -560,6 +560,8 @@ const ONYXKEYS = {
ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT: 'issueNewExpensifyCardFormDraft',
SAGE_INTACCT_CREDENTIALS_FORM: 'sageIntacctCredentialsForm',
SAGE_INTACCT_CREDENTIALS_FORM_DRAFT: 'sageIntacctCredentialsFormDraft',
+ NETSUITE_CUSTOM_FIELD_FORM: 'netSuiteCustomFieldForm',
+ NETSUITE_CUSTOM_FIELD_FORM_DRAFT: 'netSuiteCustomFieldFormDraft',
NETSUITE_TOKEN_INPUT_FORM: 'netsuiteTokenInputForm',
NETSUITE_TOKEN_INPUT_FORM_DRAFT: 'netsuiteTokenInputFormDraft',
},
@@ -625,6 +627,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.SUBSCRIPTION_SIZE_FORM]: FormTypes.SubscriptionSizeForm;
[ONYXKEYS.FORMS.ISSUE_NEW_EXPENSIFY_CARD_FORM]: FormTypes.IssueNewExpensifyCardForm;
[ONYXKEYS.FORMS.SAGE_INTACCT_CREDENTIALS_FORM]: FormTypes.SageIntactCredentialsForm;
+ [ONYXKEYS.FORMS.NETSUITE_CUSTOM_FIELD_FORM]: FormTypes.NetSuiteCustomFieldForm;
[ONYXKEYS.FORMS.NETSUITE_TOKEN_INPUT_FORM]: FormTypes.NetSuiteTokenInputForm;
};
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 82e49e31a1662..4994d32b480cf 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -1001,6 +1001,21 @@ const ROUTES = {
getRoute: (policyID: string, importField: TupleToUnion) =>
`settings/workspaces/${policyID}/accounting/netsuite/import/mapping/${importField}` as const,
},
+ POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_MAPPING: {
+ route: 'settings/workspaces/:policyID/accounting/netsuite/import/custom/:importCustomField',
+ getRoute: (policyID: string, importCustomField: ValueOf) =>
+ `settings/workspaces/${policyID}/accounting/netsuite/import/custom/${importCustomField}` as const,
+ },
+ POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_VIEW: {
+ route: 'settings/workspaces/:policyID/accounting/netsuite/import/custom/:importCustomField/view/:valueIndex',
+ getRoute: (policyID: string, importCustomField: ValueOf, valueIndex: number) =>
+ `settings/workspaces/${policyID}/accounting/netsuite/import/custom/${importCustomField}/view/${valueIndex}` as const,
+ },
+ POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_EDIT: {
+ route: 'settings/workspaces/:policyID/accounting/netsuite/import/custom/:importCustomField/edit/:valueIndex/:fieldName',
+ getRoute: (policyID: string, importCustomField: ValueOf, valueIndex: number, fieldName: string) =>
+ `settings/workspaces/${policyID}/accounting/netsuite/import/custom/${importCustomField}/edit/${valueIndex}/${fieldName}` as const,
+ },
POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS: {
route: 'settings/workspaces/:policyID/accounting/netsuite/import/customer-projects',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/netsuite/import/customer-projects` as const,
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 875de4363028a..57efec10b7eca 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -280,6 +280,9 @@ const SCREENS = {
XERO_BILL_PAYMENT_ACCOUNT_SELECTOR: 'Policy_Accounting_Xero_Bill_Payment_Account_Selector',
XERO_EXPORT_BANK_ACCOUNT_SELECT: 'Policy_Accounting_Xero_Export_Bank_Account_Select',
NETSUITE_IMPORT_MAPPING: 'Policy_Accounting_NetSuite_Import_Mapping',
+ NETSUITE_IMPORT_CUSTOM_FIELD: 'Policy_Accounting_NetSuite_Import_Custom_Field',
+ NETSUITE_IMPORT_CUSTOM_FIELD_VIEW: 'Policy_Accounting_NetSuite_Import_Custom_Field_View',
+ NETSUITE_IMPORT_CUSTOM_FIELD_EDIT: 'Policy_Accounting_NetSuite_Import_Custom_Field_Edit',
NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS: 'Policy_Accounting_NetSuite_Import_CustomersOrProjects',
NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT: 'Policy_Accounting_NetSuite_Import_CustomersOrProjects_Select',
NETSUITE_TOKEN_INPUT: 'Policy_Accounting_NetSuite_Token_Input',
diff --git a/src/components/ConnectionLayout.tsx b/src/components/ConnectionLayout.tsx
index dc8638f018d47..48f670a71e65a 100644
--- a/src/components/ConnectionLayout.tsx
+++ b/src/components/ConnectionLayout.tsx
@@ -61,8 +61,11 @@ type ConnectionLayoutProps = {
/** Name of the current connection */
connectionName: ConnectionName;
- /** Block the screen when the connection is not empty */
- reverseConnectionEmptyCheck?: boolean;
+ /** Whether or not to block user from accessing the page */
+ shouldBeBlocked?: boolean;
+
+ /** Whether the screen should load for empty connection */
+ isForEmptyConnection?: boolean;
/** Handler for back button press */
onBackButtonPress?: () => void;
@@ -97,7 +100,8 @@ function ConnectionLayout({
shouldUseScrollView = true,
headerTitleAlreadyTranslated,
titleAlreadyTranslated,
- reverseConnectionEmptyCheck = false,
+ shouldBeBlocked = false,
+ isForEmptyConnection = false,
onBackButtonPress = () => Navigation.goBack(),
}: ConnectionLayoutProps) {
const {translate} = useLocalize();
@@ -118,12 +122,14 @@ function ConnectionLayout({
[title, titleStyle, children, titleAlreadyTranslated],
);
+ const shouldBlockByConnection = isForEmptyConnection ? !isConnectionEmpty : isConnectionEmpty;
+
return (
{title}
- {!!subtitle && (
+ {(!!subtitle || !!subtitleComponent) && (
- {subtitle}
+ {subtitleComponent ?? {subtitle}}
)}
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 1607e9b858d59..4d04409431506 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -2400,8 +2400,40 @@ export default {
},
importTaxDescription: 'Import tax groups from NetSuite',
importCustomFields: {
- customSegments: 'Custom segments/records',
- customLists: 'Custom lists',
+ customSegments: {
+ title: 'Custom segments/records',
+ addButtonText: 'Add custom segment/record',
+ recordTitle: 'Custom segment',
+ helpLink: CONST.NETSUITE_IMPORT.HELP_LINKS.CUSTOM_SEGMENTS,
+ helpLinkText: 'View detailed instructions',
+ helpText: ' on configuring custom segements/records.',
+ emptyTitle: 'Add a custom segment or custom record',
+ fields: {
+ segmentName: 'Name',
+ internalID: 'Internal ID',
+ scriptID: 'Script ID',
+ mapping: 'Displayed as',
+ },
+ removeTitle: 'Remove custom segment/record',
+ removePrompt: 'Are you sure you want to remove this custom segment/record?',
+ },
+ customLists: {
+ title: 'Custom lists',
+ addButtonText: 'Add custom list',
+ recordTitle: 'Custom list',
+ helpLink: CONST.NETSUITE_IMPORT.HELP_LINKS.CUSTOM_LISTS,
+ helpLinkText: 'View detailed instructions',
+ helpText: ' on configuring custom lists.',
+ emptyTitle: 'Add a custom list',
+ fields: {
+ listName: 'Name',
+ internalID: 'Internal ID',
+ transactionFieldID: 'Transaction field ID',
+ mapping: 'Displayed as',
+ },
+ removeTitle: 'Remove custom list',
+ removePrompt: 'Are you sure you want to remove this custom list?',
+ },
},
importTypes: {
[CONST.INTEGRATION_ENTITY_MAP_TYPES.NETSUITE_DEFAULT]: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index c940fe78e7cf0..9eb0f04032a0f 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -2441,8 +2441,40 @@ export default {
},
importTaxDescription: 'Importar grupos de impuestos desde NetSuite',
importCustomFields: {
- customSegments: 'Segmentos/registros personalizados',
- customLists: 'Listas personalizado',
+ customSegments: {
+ title: 'Segmentos/registros personalizados',
+ addButtonText: 'Añadir segmento/registro personalizado',
+ recordTitle: 'Segmento personalizado',
+ helpLink: CONST.NETSUITE_IMPORT.HELP_LINKS.CUSTOM_SEGMENTS,
+ helpLinkText: 'Ver instrucciones detalladas',
+ helpText: ' sobre la configuración de segmentos/registros personalizado.',
+ emptyTitle: 'Añadir un segmento personalizado o un registro personalizado',
+ fields: {
+ segmentName: 'Name',
+ internalID: 'Internal ID',
+ scriptID: 'Script ID',
+ mapping: 'Displayed as',
+ },
+ removeTitle: 'Eliminar segmento/registro personalizado',
+ removePrompt: '¿Está seguro de que desea eliminar este segmento/registro personalizado?',
+ },
+ customLists: {
+ title: 'Listas personalizados',
+ addButtonText: 'Añadir lista personalizado',
+ recordTitle: 'Lista personalizado',
+ helpLink: CONST.NETSUITE_IMPORT.HELP_LINKS.CUSTOM_LISTS,
+ helpLinkText: 'Ver instrucciones detalladas',
+ helpText: ' sobre cómo configurar listas personalizado.',
+ emptyTitle: 'Añadir una lista personalizado',
+ fields: {
+ listName: 'Name',
+ internalID: 'Internal ID',
+ transactionFieldID: 'Transaction field ID',
+ mapping: 'Displayed as',
+ },
+ removeTitle: 'Eliminar lista personalizado',
+ removePrompt: '¿Está seguro de que desea eliminar esta lista personalizado?',
+ },
},
importTypes: {
[CONST.INTEGRATION_ENTITY_MAP_TYPES.NETSUITE_DEFAULT]: {
diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts
index 9bcc7972d5266..7b2a039c61a33 100644
--- a/src/libs/API/types.ts
+++ b/src/libs/API/types.ts
@@ -257,6 +257,8 @@ const WRITE_COMMANDS = {
UPDATE_NETSUITE_TAX_POSTING_ACCOUNT: 'UpdateNetSuiteTaxPostingAccount',
UPDATE_NETSUITE_ALLOW_FOREIGN_CURRENCY: 'UpdateNetSuiteAllowForeignCurrency',
UPDATE_NETSUITE_EXPORT_TO_NEXT_OPEN_PERIOD: 'UpdateNetSuiteExportToNextOpenPeriod',
+ UPDATE_NETSUITE_CUSTOM_SEGMENTS: 'UpdateNetSuiteCustomSegments',
+ UPDATE_NETSUITE_CUSTOM_LISTS: 'UpdateNetSuiteCustomLists',
UPDATE_NETSUITE_AUTO_SYNC: 'UpdateNetSuiteAutoSync',
UPDATE_NETSUITE_SYNC_REIMBURSED_REPORTS: 'UpdateNetSuiteSyncReimbursedReports',
UPDATE_NETSUITE_SYNC_PEOPLE: 'UpdateNetSuiteSyncPeople',
@@ -534,6 +536,9 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.UPDATE_NETSUITE_TAX_POSTING_ACCOUNT]: Parameters.UpdateNetSuiteGenericTypeParams<'bankAccountID', string>;
[WRITE_COMMANDS.UPDATE_NETSUITE_ALLOW_FOREIGN_CURRENCY]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>;
[WRITE_COMMANDS.UPDATE_NETSUITE_EXPORT_TO_NEXT_OPEN_PERIOD]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>;
+ [WRITE_COMMANDS.UPDATE_NETSUITE_EXPORT_TO_NEXT_OPEN_PERIOD]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>;
+ [WRITE_COMMANDS.UPDATE_NETSUITE_CUSTOM_SEGMENTS]: Parameters.UpdateNetSuiteGenericTypeParams<'customSegments', string>; // JSON string NetSuiteCustomSegment[]
+ [WRITE_COMMANDS.UPDATE_NETSUITE_CUSTOM_LISTS]: Parameters.UpdateNetSuiteGenericTypeParams<'customLists', string>; // JSON string NetSuiteCustomList[]
[WRITE_COMMANDS.UPDATE_NETSUITE_AUTO_SYNC]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>;
[WRITE_COMMANDS.UPDATE_NETSUITE_SYNC_REIMBURSED_REPORTS]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>;
[WRITE_COMMANDS.UPDATE_NETSUITE_SYNC_PEOPLE]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>;
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index fe631e4cd0b1a..40d93a0b19485 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -324,6 +324,12 @@ const SettingsModalStackNavigator = createModalStackNavigator('../../../../pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteTokenInputPage').default,
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT]: () => require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportPage').default,
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING]: () => require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportMappingPage').default,
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD]: () =>
+ require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldPage').default,
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW]: () =>
+ require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldView').default,
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT]: () =>
+ require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldEdit').default,
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS]: () =>
require('../../../../pages/workspace/accounting/netsuite/import/NetSuiteImportCustomersOrProjectsPage').default,
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT]: () =>
diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts
index 78732767f4c1b..83bc3078b060f 100755
--- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts
+++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts
@@ -59,6 +59,9 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = {
SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TOKEN_INPUT,
SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT,
SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING,
+ SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD,
+ SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW,
+ SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT,
SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS,
SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT,
SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT,
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index eb2646a048c76..95ad12cd7df9d 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -357,6 +357,9 @@ const config: LinkingOptions['config'] = {
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TOKEN_INPUT]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.route},
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT.route},
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_MAPPING.route},
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_MAPPING.route},
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_VIEW.route},
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_EDIT.route},
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS.route},
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT]: {path: ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT.route},
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT]: {
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 183e21fc67b40..fdd8ddd452ad9 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -432,6 +432,21 @@ type SettingsNavigatorParamList = {
policyID: string;
importField: TupleToUnion;
};
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD]: {
+ policyID: string;
+ importCustomField: TupleToUnion;
+ };
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW]: {
+ policyID: string;
+ importCustomField: TupleToUnion;
+ internalID: string;
+ };
+ [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT]: {
+ policyID: string;
+ importCustomField: TupleToUnion;
+ internalID: string;
+ fieldName: string;
+ };
[SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT]: {
policyID: string;
};
diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts
index 4c071317907b9..2f7e5136f2b63 100644
--- a/src/libs/PolicyUtils.ts
+++ b/src/libs/PolicyUtils.ts
@@ -8,7 +8,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {OnyxInputOrEntry, Policy, PolicyCategories, PolicyEmployeeList, PolicyTagList, PolicyTags, TaxRate} from '@src/types/onyx';
-import type {ConnectionLastSync, Connections, CustomUnit, NetSuiteConnection, PolicyFeatureName, Rate, Tenant} from '@src/types/onyx/Policy';
+import type {ConnectionLastSync, Connections, CustomUnit, NetSuiteConnection, NetSuiteCustomList, NetSuiteCustomSegment, PolicyFeatureName, Rate, Tenant} from '@src/types/onyx/Policy';
import type PolicyEmployee from '@src/types/onyx/PolicyEmployee';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import Navigation from './Navigation/Navigation';
@@ -565,6 +565,14 @@ function getCustomersOrJobsLabelNetSuite(policy: Policy | undefined, translate:
return importedValueLabel.charAt(0).toUpperCase() + importedValueLabel.slice(1);
}
+function isCustomSegmentRecord(customRecord: NetSuiteCustomList | NetSuiteCustomSegment): boolean {
+ return 'segmentName' in customRecord;
+}
+
+function getNameFromCustomSegmentRecord(customRecord: NetSuiteCustomList | NetSuiteCustomSegment): string {
+ return 'segmentName' in customRecord ? customRecord.segmentName : customRecord.listName;
+}
+
function getIntegrationLastSuccessfulDate(connection?: Connections[keyof Connections]) {
if (!connection) {
return undefined;
@@ -682,6 +690,8 @@ export {
getIntegrationLastSuccessfulDate,
getCurrentConnectionName,
getCustomersOrJobsLabelNetSuite,
+ isCustomSegmentRecord,
+ getNameFromCustomSegmentRecord,
};
export type {MemberEmailsToAccountIDs};
diff --git a/src/libs/actions/connections/NetSuiteCommands.ts b/src/libs/actions/connections/NetSuiteCommands.ts
index 20f7fcd6e483d..b6b6e01657fcc 100644
--- a/src/libs/actions/connections/NetSuiteCommands.ts
+++ b/src/libs/actions/connections/NetSuiteCommands.ts
@@ -7,7 +7,7 @@ import {WRITE_COMMANDS} from '@libs/API/types';
import * as ErrorUtils from '@libs/ErrorUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
-import type {Connections} from '@src/types/onyx/Policy';
+import type {Connections, NetSuiteCustomList, NetSuiteCustomSegment} from '@src/types/onyx/Policy';
import type {OnyxData} from '@src/types/onyx/Request';
type SubsidiaryParam = {
@@ -427,6 +427,31 @@ function updateNetSuiteCrossSubsidiaryCustomersConfiguration(policyID: string, i
API.write(WRITE_COMMANDS.UPDATE_NETSUITE_CROSS_SUBSIDIARY_CUSTOMER_CONFIGURATION, params, onyxData);
}
+function updateNetSuiteCustomSegments(policyID: string, records: NetSuiteCustomSegment[], oldRecords: NetSuiteCustomSegment[]) {
+ const onyxData = updateNetSuiteSyncOptionsOnyxData(policyID, 'customSegments', records, oldRecords);
+
+ API.write(
+ WRITE_COMMANDS.UPDATE_NETSUITE_CUSTOM_SEGMENTS,
+ {
+ policyID,
+ customSegments: JSON.stringify(records),
+ },
+ onyxData,
+ );
+}
+
+function updateNetSuiteCustomLists(policyID: string, records: NetSuiteCustomList[], oldRecords: NetSuiteCustomList[]) {
+ const onyxData = updateNetSuiteSyncOptionsOnyxData(policyID, 'customLists', records, oldRecords);
+ API.write(
+ WRITE_COMMANDS.UPDATE_NETSUITE_CUSTOM_LISTS,
+ {
+ policyID,
+ customLists: JSON.stringify(records),
+ },
+ onyxData,
+ );
+}
+
function updateNetSuiteExporter(policyID: string, exporter: string, oldExporter: string) {
const onyxData = updateNetSuiteOnyxData(policyID, CONST.NETSUITE_CONFIG.EXPORTER, exporter, oldExporter);
@@ -749,6 +774,8 @@ export {
updateNetSuiteExportToNextOpenPeriod,
updateNetSuiteImportMapping,
updateNetSuiteCrossSubsidiaryCustomersConfiguration,
+ updateNetSuiteCustomSegments,
+ updateNetSuiteCustomLists,
updateNetSuiteAutoSync,
updateNetSuiteSyncReimbursedReports,
updateNetSuiteSyncPeople,
diff --git a/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteTokenInputPage.tsx b/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteTokenInputPage.tsx
index 41d4282571639..579f89249a34e 100644
--- a/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteTokenInputPage.tsx
+++ b/src/pages/workspace/accounting/netsuite/NetSuiteTokenInput/NetSuiteTokenInputPage.tsx
@@ -60,8 +60,8 @@ function NetSuiteTokenInputPage({policy}: WithPolicyConnectionsProps) {
featureName={CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED}
contentContainerStyle={[styles.flex1]}
titleStyle={styles.ph5}
- reverseConnectionEmptyCheck
- connectionName={CONST.POLICY.CONNECTIONS.NAME.XERO}
+ isForEmptyConnection
+ connectionName={CONST.POLICY.CONNECTIONS.NAME.NETSUITE}
onBackButtonPress={handleBackButtonPress}
shouldIncludeSafeAreaPaddingBottom
>
diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldEdit.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldEdit.tsx
new file mode 100644
index 0000000000000..5cc6bc9f04dbf
--- /dev/null
+++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldEdit.tsx
@@ -0,0 +1,170 @@
+import React, {useCallback, useMemo} from 'react';
+import type {ValueOf} from 'type-fest';
+import ConnectionLayout from '@components/ConnectionLayout';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
+import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
+import SelectionList from '@components/SelectionList';
+import RadioListItem from '@components/SelectionList/RadioListItem';
+import type {SelectorType} from '@components/SelectionScreen';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {updateNetSuiteCustomLists, updateNetSuiteCustomSegments} from '@libs/actions/connections/NetSuiteCommands';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import withPolicyConnections from '@pages/workspace/withPolicyConnections';
+import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import type {NetSuiteCustomList, NetSuiteCustomSegment} from '@src/types/onyx/Policy';
+
+type CustomRecord = NetSuiteCustomList | NetSuiteCustomSegment;
+type ImportCustomFieldsKeys = ValueOf;
+type ImportListItem = SelectorType & {
+ value: ValueOf;
+};
+
+type NetSuiteImportCustomFieldViewProps = WithPolicyConnectionsProps & {
+ route: {
+ params: {
+ importCustomField: ImportCustomFieldsKeys;
+ valueIndex: number;
+ fieldName: string;
+ };
+ };
+};
+
+function NetSuiteImportCustomFieldEdit({
+ policy,
+ route: {
+ params: {importCustomField, valueIndex, fieldName},
+ },
+}: NetSuiteImportCustomFieldViewProps) {
+ const policyID = policy?.id ?? '-1';
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+
+ const config = policy?.connections?.netsuite?.options?.config;
+ const allRecords = useMemo(() => config?.syncOptions?.[importCustomField] ?? [], [config?.syncOptions, importCustomField]);
+
+ const customRecord: CustomRecord | undefined = allRecords[valueIndex];
+ const fieldValue = customRecord?.[fieldName as keyof CustomRecord] ?? '';
+
+ const updateRecord = useCallback(
+ (formValues: Partial>) => {
+ const newValue = formValues[fieldName as keyof typeof formValues];
+
+ if (customRecord) {
+ const updatedRecords = allRecords.map((record, index) => {
+ if (index === Number(valueIndex)) {
+ return {
+ ...record,
+ [fieldName]: newValue,
+ };
+ }
+ return record;
+ });
+
+ if (PolicyUtils.isCustomSegmentRecord(customRecord)) {
+ updateNetSuiteCustomSegments(policyID, updatedRecords as NetSuiteCustomSegment[], allRecords as NetSuiteCustomSegment[]);
+ } else {
+ updateNetSuiteCustomLists(policyID, updatedRecords as NetSuiteCustomList[], allRecords as NetSuiteCustomList[]);
+ }
+ }
+
+ Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_VIEW.getRoute(policyID, importCustomField, valueIndex));
+ },
+ [allRecords, customRecord, fieldName, importCustomField, policyID, valueIndex],
+ );
+
+ const validate = useCallback(
+ (formValues: FormOnyxValues) => {
+ const errors: FormInputErrors = {};
+
+ const key = fieldName as keyof typeof formValues;
+ if (!formValues[key]) {
+ ErrorUtils.addErrorMessage(errors, fieldName, translate('common.error.fieldRequired'));
+ }
+
+ return errors;
+ },
+ [fieldName, translate],
+ );
+
+ const renderForm = useMemo(
+ () =>
+ customRecord && (
+
+
+
+ ),
+ [customRecord, fieldName, fieldValue, importCustomField, styles.flexGrow1, styles.ph5, translate, updateRecord, validate],
+ );
+
+ const renderSelection = useMemo(() => {
+ const options = [CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD];
+
+ const selectionData: ImportListItem[] =
+ options.map((option) => ({
+ text: translate(`workspace.netsuite.import.importTypes.${option}.label`),
+ keyForList: option,
+ isSelected: fieldValue === option,
+ value: option,
+ alternateText: translate(`workspace.netsuite.import.importTypes.${option}.description`),
+ })) ?? [];
+
+ return (
+ customRecord && (
+
+ updateRecord({
+ [fieldName]: selected.value,
+ })
+ }
+ sections={[{data: selectionData}]}
+ ListItem={RadioListItem}
+ initiallyFocusedOptionKey={selectionData?.find((record) => record.isSelected)?.keyForList}
+ />
+ )
+ );
+ }, [customRecord, fieldName, fieldValue, translate, updateRecord]);
+
+ return (
+
+ {fieldName === 'mapping' ? renderSelection : renderForm}
+
+ );
+}
+
+NetSuiteImportCustomFieldEdit.displayName = 'NetSuiteImportCustomFieldEdit';
+export default withPolicyConnections(NetSuiteImportCustomFieldEdit);
diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldPage.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldPage.tsx
new file mode 100644
index 0000000000000..ce7fc22ba5866
--- /dev/null
+++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldPage.tsx
@@ -0,0 +1,136 @@
+import React, {useMemo} from 'react';
+import type {StyleProp, TextStyle} from 'react-native';
+import {View} from 'react-native';
+import type {ValueOf} from 'type-fest';
+import Button from '@components/Button';
+import ConnectionLayout from '@components/ConnectionLayout';
+import FixedFooter from '@components/FixedFooter';
+import * as Illustrations from '@components/Icon/Illustrations';
+import type {LocaleContextProps} from '@components/LocaleContextProvider';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import WorkspaceEmptyStateSection from '@components/WorkspaceEmptyStateSection';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Navigation from '@libs/Navigation/Navigation';
+import withPolicyConnections from '@pages/workspace/withPolicyConnections';
+import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
+import type {ThemeStyles} from '@styles/index';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
+
+type ImportCustomFieldsKeys = ValueOf;
+
+type NetSuiteImportCustomFieldPageProps = WithPolicyConnectionsProps & {
+ route: {
+ params: {
+ importCustomField: ImportCustomFieldsKeys;
+ };
+ };
+};
+
+type HelpLinkComponentProps = {
+ importCustomField: ImportCustomFieldsKeys;
+ translate: LocaleContextProps['translate'];
+ styles: ThemeStyles;
+ alignmentStyle: StyleProp;
+};
+
+function HelpLinkComponent({importCustomField, styles, translate, alignmentStyle}: HelpLinkComponentProps) {
+ return (
+
+
+ {translate(`workspace.netsuite.import.importCustomFields.${importCustomField}.helpLinkText`)}
+
+ {translate(`workspace.netsuite.import.importCustomFields.${importCustomField}.helpText`)}
+
+ );
+}
+
+function NetSuiteImportCustomFieldPage({
+ policy,
+ route: {
+ params: {importCustomField},
+ },
+}: NetSuiteImportCustomFieldPageProps) {
+ const policyID = policy?.id ?? '-1';
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+
+ const config = policy?.connections?.netsuite?.options?.config;
+ const data = config?.syncOptions?.[importCustomField] ?? [];
+
+ const listEmptyComponent = useMemo(
+ () => (
+
+ }
+ containerStyle={[styles.flex1, styles.justifyContentCenter]}
+ />
+ ),
+ [importCustomField, styles, translate],
+ );
+
+ const listHeaderComponent = useMemo(
+ () => (
+
+
+
+ ),
+ [styles, importCustomField, translate],
+ );
+
+ return (
+
+ {data.length === 0 ? listEmptyComponent : listHeaderComponent}
+
+ {data.map((record, index) => (
+ Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_VIEW.getRoute(policyID, importCustomField, index))}
+ />
+ ))}
+
+
+
+
+
+ );
+}
+
+NetSuiteImportCustomFieldPage.displayName = 'NetSuiteImportCustomFieldPage';
+export default withPolicyConnections(NetSuiteImportCustomFieldPage);
diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldView.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldView.tsx
new file mode 100644
index 0000000000000..7fda7be968c76
--- /dev/null
+++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportCustomFieldView.tsx
@@ -0,0 +1,111 @@
+import React, {useCallback, useMemo, useState} from 'react';
+import type {ValueOf} from 'type-fest';
+import ConfirmModal from '@components/ConfirmModal';
+import ConnectionLayout from '@components/ConnectionLayout';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {updateNetSuiteCustomLists, updateNetSuiteCustomSegments} from '@libs/actions/connections/NetSuiteCommands';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import withPolicyConnections from '@pages/workspace/withPolicyConnections';
+import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+import ROUTES from '@src/ROUTES';
+import type {NetSuiteCustomList, NetSuiteCustomSegment} from '@src/types/onyx/Policy';
+
+type CustomRecord = NetSuiteCustomList | NetSuiteCustomSegment;
+type ImportCustomFieldsKeys = ValueOf;
+
+type NetSuiteImportCustomFieldViewProps = WithPolicyConnectionsProps & {
+ route: {
+ params: {
+ importCustomField: ImportCustomFieldsKeys;
+ valueIndex: number;
+ };
+ };
+};
+
+function NetSuiteImportCustomFieldView({
+ policy,
+ route: {
+ params: {importCustomField, valueIndex},
+ },
+}: NetSuiteImportCustomFieldViewProps) {
+ const policyID = policy?.id ?? '-1';
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+ const [isRemoveModalOpen, setIsRemoveModalOpen] = useState(false);
+
+ const config = policy?.connections?.netsuite?.options?.config;
+ const allRecords = useMemo(() => config?.syncOptions?.[importCustomField] ?? [], [config?.syncOptions, importCustomField]);
+
+ const customRecord: CustomRecord | undefined = allRecords[valueIndex];
+ const fieldList = customRecord && PolicyUtils.isCustomSegmentRecord(customRecord) ? CONST.NETSUITE_CONFIG.CUSTOM_SEGMENT_FIELDS : CONST.NETSUITE_CONFIG.CUSTOM_LIST_FIELDS;
+
+ const removeRecord = useCallback(() => {
+ if (customRecord) {
+ const filteredRecords = allRecords.filter((record) => record.internalID !== customRecord?.internalID);
+ if (PolicyUtils.isCustomSegmentRecord(customRecord)) {
+ updateNetSuiteCustomSegments(policyID, filteredRecords as NetSuiteCustomSegment[], allRecords as NetSuiteCustomSegment[]);
+ } else {
+ updateNetSuiteCustomLists(policyID, filteredRecords as NetSuiteCustomList[], allRecords as NetSuiteCustomList[]);
+ }
+ }
+ Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_MAPPING.getRoute(policyID, importCustomField));
+ }, [allRecords, customRecord, importCustomField, policyID]);
+
+ return (
+
+ {customRecord && (
+ <>
+ {fieldList.map((fieldName) => (
+ Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_EDIT.getRoute(policyID, importCustomField, valueIndex, fieldName))}
+ />
+ ))}
+
+ );
+}
+
+NetSuiteImportCustomFieldView.displayName = 'NetSuiteImportCustomFieldView';
+export default withPolicyConnections(NetSuiteImportCustomFieldView);
diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx
index 17256defc0a81..4b2dc4809a846 100644
--- a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx
+++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx
@@ -111,7 +111,7 @@ function NetSuiteImportPage({policy}: WithPolicyConnectionsProps) {
/>
)}
- {CONST.NETSUITE_CONFIG.IMPORT_CUSTOM_FIELDS.map((importField) => (
+ {Object.values(CONST.NETSUITE_CONFIG.IMPORT_CUSTOM_FIELDS).map((importField) => (
Policy.clearNetSuiteErrorField(policyID, importField)}
>
{
- // TODO: Navigation will be handled in future PRs
- }}
+ onPress={() => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_MAPPING.getRoute(policyID, importField))}
brickRoadIndicator={config?.errorFields?.[importField] ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
/>
diff --git a/src/types/form/NetSuiteCustomFieldForm.ts b/src/types/form/NetSuiteCustomFieldForm.ts
new file mode 100644
index 0000000000000..ee874c19432de
--- /dev/null
+++ b/src/types/form/NetSuiteCustomFieldForm.ts
@@ -0,0 +1,28 @@
+import type {ValueOf} from 'type-fest';
+import type Form from './Form';
+
+const INPUT_IDS = {
+ INTERNAL_ID: 'internalID',
+ MAPPING: 'mapping',
+ LIST_NAME: 'listName',
+ SEGMENT_NAME: 'segmentName',
+ TRANSACTION_FIELD_ID: 'transactionFieldID',
+ SCRIPT_ID: 'scriptID',
+} as const;
+
+type InputID = ValueOf;
+
+type NetSuiteCustomFieldForm = Form<
+ InputID,
+ {
+ [INPUT_IDS.INTERNAL_ID]: string;
+ [INPUT_IDS.MAPPING]: string;
+ [INPUT_IDS.LIST_NAME]: string;
+ [INPUT_IDS.SEGMENT_NAME]: string;
+ [INPUT_IDS.TRANSACTION_FIELD_ID]: string;
+ [INPUT_IDS.SCRIPT_ID]: string;
+ }
+>;
+
+export type {NetSuiteCustomFieldForm};
+export default INPUT_IDS;
diff --git a/src/types/form/index.ts b/src/types/form/index.ts
index b3503099b4b31..359ef653f34a3 100644
--- a/src/types/form/index.ts
+++ b/src/types/form/index.ts
@@ -56,5 +56,6 @@ export type {WorkForm} from './WorkForm';
export type {SubscriptionSizeForm} from './SubscriptionSizeForm';
export type {WorkspaceReportFieldsForm} from './WorkspaceReportFieldsForm';
export type {SageIntactCredentialsForm} from './SageIntactCredentialsForm';
+export type {NetSuiteCustomFieldForm} from './NetSuiteCustomFieldForm';
export type {NetSuiteTokenInputForm} from './NetSuiteTokenInputForm';
export type {default as Form} from './Form';
diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts
index 098869d7bf8e6..e54ea15034282 100644
--- a/src/types/onyx/Policy.ts
+++ b/src/types/onyx/Policy.ts
@@ -718,6 +718,36 @@ type NetSuiteCustomFormIDOptions = {
journalEntry?: string;
};
+/** NetSuite custom list */
+type NetSuiteCustomList = {
+ /** The name of the custom list in NetSuite */
+ listName: string;
+
+ /** The internalID of the custom list in NetSuite */
+ internalID: string;
+
+ /** The ID of the transaction form field we'll code the list option onto during Export */
+ transactionFieldID: string;
+
+ /** Whether we import this list as a report field or tag */
+ mapping: 'tag' | 'reportField';
+};
+
+/** NetSuite custom segments/records */
+type NetSuiteCustomSegment = {
+ /** The name of the custom segment */
+ segmentName: string;
+
+ /** The ID of the custom segment in NetSuite */
+ internalID: string;
+
+ /** The ID of the transaction form field we'll code this segment onto during Export */
+ scriptID: string;
+
+ /** Whether we import this segment as a report field or tag */
+ mapping: 'tag' | 'reportField';
+};
+
/** User configuration for the NetSuite accounting integration. */
type NetSuiteConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{
/** Invoice Item Preference */
@@ -783,19 +813,7 @@ type NetSuiteConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{
syncReimbursedReports: boolean;
/** The relevant details of the custom segments we import into Expensify and code onto expenses */
- customSegments?: Array<{
- /** The name of the custom segment */
- segmentName: string;
-
- /** The ID of the custom segment in NetSuite */
- internalID: string;
-
- /** The ID of the transaction form field we'll code this segment onto during Export */
- scriptID: string;
-
- /** Whether we import this segment as a report field or tag */
- mapping: 'tag' | 'reportField';
- }>;
+ customSegments?: NetSuiteCustomSegment[];
/** Whether to import Employees from NetSuite into Expensify */
syncPeople: boolean;
@@ -816,19 +834,7 @@ type NetSuiteConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{
syncCustomSegments?: boolean;
/** The relevant details of the custom lists we import into Expensify and code onto expenses */
- customLists?: Array<{
- /** The name of the custom list in NetSuite */
- listName: string;
-
- /** The internalID of the custom list in NetSuite */
- internalID: string;
-
- /** The ID of the transaction form field we'll code the list option onto during Export */
- transactionFieldID: string;
-
- /** Whether we import this list as a report field or tag */
- mapping: 'tag' | 'reportField';
- }>;
+ customLists?: NetSuiteCustomList[];
/** Whether we'll import Expense Categories into Expensify as categories */
syncCategories: boolean;
@@ -1355,4 +1361,6 @@ export type {
NetSuiteConnection,
ConnectionLastSync,
NetSuiteSubsidiary,
+ NetSuiteCustomList,
+ NetSuiteCustomSegment,
};