Skip to content

Commit

Permalink
Merge pull request Expensify#46201 from shubham1206agra/netsuite-fixes
Browse files Browse the repository at this point in the history
Netsuite fixes
  • Loading branch information
yuwenmemon authored Jul 29, 2024
2 parents bba5e27 + 2159ef5 commit 67493ab
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 49 deletions.
109 changes: 83 additions & 26 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ import type {
ConnectionName,
Connections,
CustomUnit,
InvoiceItem,
NetSuiteAccount,
NetSuiteConnection,
NetSuiteCustomList,
NetSuiteCustomSegment,
NetSuiteTaxAccount,
NetSuiteVendor,
PolicyFeatureName,
Rate,
Tenant,
Expand Down Expand Up @@ -549,61 +552,90 @@ function xeroSettingsPendingAction(settings?: XeroSettings, pendingFields?: Pend
return pendingFields[key ?? '-1'];
}

function findSelectedVendorWithDefaultSelect(vendors: NetSuiteVendor[] | undefined, selectedVendorId: string | undefined) {
const selectedVendor = (vendors ?? []).find(({id}) => id === selectedVendorId);
return selectedVendor ?? vendors?.[0] ?? undefined;
}

function findSelectedBankAccountWithDefaultSelect(accounts: NetSuiteAccount[] | undefined, selectedBankAccountId: string | undefined) {
const selectedBankAccount = (accounts ?? []).find(({id}) => id === selectedBankAccountId);
return selectedBankAccount ?? accounts?.[0] ?? undefined;
}

function findSelectedInvoiceItemWithDefaultSelect(invoiceItems: InvoiceItem[] | undefined, selectedItemId: string | undefined) {
const selectedInvoiceItem = (invoiceItems ?? []).find(({id}) => id === selectedItemId);
return selectedInvoiceItem ?? invoiceItems?.[0] ?? undefined;
}

function findSelectedTaxAccountWithDefaultSelect(taxAccounts: NetSuiteTaxAccount[] | undefined, selectedAccountId: string | undefined) {
const selectedTaxAccount = (taxAccounts ?? []).find(({externalID}) => externalID === selectedAccountId);
return selectedTaxAccount ?? taxAccounts?.[0] ?? undefined;
}

function getNetSuiteVendorOptions(policy: Policy | undefined, selectedVendorId: string | undefined): SelectorType[] {
const vendors = policy?.connections?.netsuite.options.data.vendors ?? [];
const vendors = policy?.connections?.netsuite.options.data.vendors;

const selectedVendor = findSelectedVendorWithDefaultSelect(vendors, selectedVendorId);

return (vendors ?? []).map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: selectedVendorId === id,
isSelected: selectedVendor?.id === id,
}));
}

function getNetSuitePayableAccountOptions(policy: Policy | undefined, selectedBankAccountId: string | undefined): SelectorType[] {
const payableAccounts = policy?.connections?.netsuite.options.data.payableList ?? [];
const payableAccounts = policy?.connections?.netsuite.options.data.payableList;

const selectedPayableAccount = findSelectedBankAccountWithDefaultSelect(payableAccounts, selectedBankAccountId);

return (payableAccounts ?? []).map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: selectedBankAccountId === id,
isSelected: selectedPayableAccount?.id === id,
}));
}

function getNetSuiteReceivableAccountOptions(policy: Policy | undefined, selectedBankAccountId: string | undefined): SelectorType[] {
const receivableAccounts = policy?.connections?.netsuite.options.data.receivableList ?? [];
const receivableAccounts = policy?.connections?.netsuite.options.data.receivableList;

const selectedReceivableAccount = findSelectedBankAccountWithDefaultSelect(receivableAccounts, selectedBankAccountId);

return (receivableAccounts ?? []).map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: selectedBankAccountId === id,
isSelected: selectedReceivableAccount?.id === id,
}));
}

function getNetSuiteInvoiceItemOptions(policy: Policy | undefined, selectedItemId: string | undefined): SelectorType[] {
const invoiceItems = policy?.connections?.netsuite.options.data.items ?? [];
const invoiceItems = policy?.connections?.netsuite.options.data.items;

const selectedInvoiceItem = findSelectedInvoiceItemWithDefaultSelect(invoiceItems, selectedItemId);

return (invoiceItems ?? []).map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: selectedItemId === id,
isSelected: selectedInvoiceItem?.id === id,
}));
}

function getNetSuiteTaxAccountOptions(policy: Policy | undefined, subsidiaryCountry?: string, selectedAccountId?: string): SelectorType[] {
const taxAccounts = policy?.connections?.netsuite.options.data.taxAccountsList ?? [];
const taxAccounts = policy?.connections?.netsuite.options.data.taxAccountsList;
const accountOptions = (taxAccounts ?? []).filter(({country}) => country === subsidiaryCountry);

return (taxAccounts ?? [])
.filter(({country}) => country === subsidiaryCountry)
.map(({externalID, name}) => ({
value: externalID,
text: name,
keyForList: externalID,
isSelected: selectedAccountId === externalID,
}));
const selectedTaxAccount = findSelectedTaxAccountWithDefaultSelect(accountOptions, selectedAccountId);

return accountOptions.map(({externalID, name}) => ({
value: externalID,
text: name,
keyForList: externalID,
isSelected: selectedTaxAccount?.externalID === externalID,
}));
}

function canUseTaxNetSuite(canUseNetSuiteUSATax?: boolean, subsidiaryCountry?: string) {
Expand All @@ -614,44 +646,62 @@ function canUseProvincialTaxNetSuite(subsidiaryCountry?: string) {
return subsidiaryCountry === '_canada';
}

function getFilteredReimbursableAccountOptions(payableAccounts: NetSuiteAccount[] | undefined) {
return (payableAccounts ?? []).filter(({type}) => type === CONST.NETSUITE_ACCOUNT_TYPE.BANK || type === CONST.NETSUITE_ACCOUNT_TYPE.CREDIT_CARD);
}

function getNetSuiteReimbursableAccountOptions(policy: Policy | undefined, selectedBankAccountId: string | undefined): SelectorType[] {
const payableAccounts = policy?.connections?.netsuite.options.data.payableList ?? [];
const accountOptions = (payableAccounts ?? []).filter(({type}) => type === CONST.NETSUITE_ACCOUNT_TYPE.BANK || type === CONST.NETSUITE_ACCOUNT_TYPE.CREDIT_CARD);
const payableAccounts = policy?.connections?.netsuite.options.data.payableList;
const accountOptions = getFilteredReimbursableAccountOptions(payableAccounts);

const selectedPayableAccount = findSelectedBankAccountWithDefaultSelect(accountOptions, selectedBankAccountId);

return accountOptions.map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: selectedBankAccountId === id,
isSelected: selectedPayableAccount?.id === id,
}));
}

function getFilteredCollectionAccountOptions(payableAccounts: NetSuiteAccount[] | undefined) {
return (payableAccounts ?? []).filter(({type}) => type === CONST.NETSUITE_ACCOUNT_TYPE.BANK);
}

function getNetSuiteCollectionAccountOptions(policy: Policy | undefined, selectedBankAccountId: string | undefined): SelectorType[] {
const payableAccounts = policy?.connections?.netsuite.options.data.payableList ?? [];
const accountOptions = (payableAccounts ?? []).filter(({type}) => type === CONST.NETSUITE_ACCOUNT_TYPE.BANK);
const payableAccounts = policy?.connections?.netsuite.options.data.payableList;
const accountOptions = getFilteredCollectionAccountOptions(payableAccounts);

const selectedPayableAccount = findSelectedBankAccountWithDefaultSelect(accountOptions, selectedBankAccountId);

return accountOptions.map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: selectedBankAccountId === id,
isSelected: selectedPayableAccount?.id === id,
}));
}

function getFilteredApprovalAccountOptions(payableAccounts: NetSuiteAccount[] | undefined) {
return (payableAccounts ?? []).filter(({type}) => type === CONST.NETSUITE_ACCOUNT_TYPE.ACCOUNTS_PAYABLE);
}

function getNetSuiteApprovalAccountOptions(policy: Policy | undefined, selectedBankAccountId: string | undefined): SelectorType[] {
const payableAccounts = policy?.connections?.netsuite.options.data.payableList ?? [];
const payableAccounts = policy?.connections?.netsuite.options.data.payableList;
const defaultApprovalAccount: NetSuiteAccount = {
id: CONST.NETSUITE_APPROVAL_ACCOUNT_DEFAULT,
name: Localize.translateLocal('workspace.netsuite.advancedConfig.defaultApprovalAccount'),
type: CONST.NETSUITE_ACCOUNT_TYPE.ACCOUNTS_PAYABLE,
};
const accountOptions = [defaultApprovalAccount].concat((payableAccounts ?? []).filter(({type}) => type === CONST.NETSUITE_ACCOUNT_TYPE.ACCOUNTS_PAYABLE));
const accountOptions = getFilteredApprovalAccountOptions([defaultApprovalAccount].concat(payableAccounts ?? []));

const selectedPayableAccount = findSelectedBankAccountWithDefaultSelect(accountOptions, selectedBankAccountId);

return accountOptions.map(({id, name}) => ({
value: id,
text: name,
keyForList: id,
isSelected: selectedBankAccountId === id,
isSelected: selectedPayableAccount?.id === id,
}));
}

Expand Down Expand Up @@ -874,11 +924,18 @@ export {
findCurrentXeroOrganization,
getCurrentXeroOrganizationName,
getXeroBankAccountsWithDefaultSelect,
findSelectedVendorWithDefaultSelect,
findSelectedBankAccountWithDefaultSelect,
findSelectedInvoiceItemWithDefaultSelect,
findSelectedTaxAccountWithDefaultSelect,
getNetSuiteVendorOptions,
canUseTaxNetSuite,
canUseProvincialTaxNetSuite,
getFilteredReimbursableAccountOptions,
getNetSuiteReimbursableAccountOptions,
getFilteredCollectionAccountOptions,
getNetSuiteCollectionAccountOptions,
getFilteredApprovalAccountOptions,
getNetSuiteApprovalAccountOptions,
getNetSuitePayableAccountOptions,
getNetSuiteReceivableAccountOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import * as Connections from '@libs/actions/connections/NetSuiteCommands';
import * as ErrorUtils from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
import {findSelectedBankAccountWithDefaultSelect, getFilteredApprovalAccountOptions, getFilteredCollectionAccountOptions, getFilteredReimbursableAccountOptions} from '@libs/PolicyUtils';
import type {DividerLineItem, MenuItem, ToggleItem} from '@pages/workspace/accounting/netsuite/types';
import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
import withPolicyConnections from '@pages/workspace/withPolicyConnections';
Expand All @@ -27,18 +28,21 @@ function NetSuiteAdvancedPage({policy}: WithPolicyConnectionsProps) {
const {payableList} = policy?.connections?.netsuite?.options?.data ?? {};

const selectedReimbursementAccount = useMemo(
() => (payableList ?? []).find((payableAccount) => payableAccount.id === config?.reimbursementAccountID),
() => findSelectedBankAccountWithDefaultSelect(getFilteredReimbursableAccountOptions(payableList), config?.reimbursementAccountID),
[payableList, config?.reimbursementAccountID],
);
const selectedCollectionAccount = useMemo(() => (payableList ?? []).find((payableAccount) => payableAccount.id === config?.collectionAccount), [payableList, config?.collectionAccount]);
const selectedCollectionAccount = useMemo(
() => findSelectedBankAccountWithDefaultSelect(getFilteredCollectionAccountOptions(payableList), config?.collectionAccount),
[payableList, config?.collectionAccount],
);
const selectedApprovalAccount = useMemo(() => {
if (config?.approvalAccount === CONST.NETSUITE_APPROVAL_ACCOUNT_DEFAULT) {
return {
id: CONST.NETSUITE_APPROVAL_ACCOUNT_DEFAULT,
name: translate('workspace.netsuite.advancedConfig.defaultApprovalAccount'),
};
}
return (payableList ?? []).find((payableAccount) => payableAccount.id === config?.approvalAccount);
return findSelectedBankAccountWithDefaultSelect(getFilteredApprovalAccountOptions(payableList), config?.approvalAccount);
}, [config?.approvalAccount, payableList, translate]);

const menuItems: Array<MenuItem | ToggleItem | DividerLineItem> = [
Expand Down Expand Up @@ -207,7 +211,7 @@ function NetSuiteAdvancedPage({policy}: WithPolicyConnectionsProps) {
description: translate('workspace.netsuite.advancedConfig.customFormIDReimbursable'),
onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_CUSTOM_FORM_ID.getRoute(policyID, CONST.NETSUITE_EXPENSE_TYPE.REIMBURSABLE)),
brickRoadIndicator: config?.errorFields?.customFormIDOptions ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
title: config?.customFormIDOptions?.reimbursable[CONST.NETSUITE_MAP_EXPORT_DESTINATION[config.reimbursableExpensesExportDestination]],
title: config?.customFormIDOptions?.reimbursable?.[CONST.NETSUITE_MAP_EXPORT_DESTINATION[config.reimbursableExpensesExportDestination]],
pendingAction: config?.pendingFields?.customFormIDOptions,
errors: ErrorUtils.getLatestErrorField(config, CONST.NETSUITE_CONFIG.CUSTOM_FORM_ID_OPTIONS),
onCloseError: () => Policy.clearNetSuiteErrorField(policyID, CONST.NETSUITE_CONFIG.CUSTOM_FORM_ID_OPTIONS),
Expand All @@ -218,7 +222,7 @@ function NetSuiteAdvancedPage({policy}: WithPolicyConnectionsProps) {
description: translate('workspace.netsuite.advancedConfig.customFormIDNonReimbursable'),
onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_CUSTOM_FORM_ID.getRoute(policyID, CONST.NETSUITE_EXPENSE_TYPE.NON_REIMBURSABLE)),
brickRoadIndicator: config?.errorFields?.customFormIDOptions ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
title: config?.customFormIDOptions?.nonReimbursable[CONST.NETSUITE_MAP_EXPORT_DESTINATION[config.nonreimbursableExpensesExportDestination]],
title: config?.customFormIDOptions?.nonReimbursable?.[CONST.NETSUITE_MAP_EXPORT_DESTINATION[config.nonreimbursableExpensesExportDestination]],
pendingAction: config?.pendingFields?.customFormIDOptions,
errors: ErrorUtils.getLatestErrorField(config, CONST.NETSUITE_CONFIG.CUSTOM_FORM_ID_OPTIONS),
onCloseError: () => Policy.clearNetSuiteErrorField(policyID, CONST.NETSUITE_CONFIG.CUSTOM_FORM_ID_OPTIONS),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ function NetSuiteDateSelectPage({policy}: WithPolicyConnectionsProps) {
const policyID = policy?.id ?? '-1';
const styles = useThemeStyles();
const config = policy?.connections?.netsuite.options.config;
const selectedValue = Object.values(CONST.NETSUITE_EXPORT_DATE).find((value) => value === config?.exportDate) ?? CONST.NETSUITE_EXPORT_DATE.LAST_EXPENSE;
const data: MenuListItem[] = Object.values(CONST.NETSUITE_EXPORT_DATE).map((dateType) => ({
value: dateType,
text: translate(`workspace.netsuite.exportDate.values.${dateType}.label`),
alternateText: translate(`workspace.netsuite.exportDate.values.${dateType}.description`),
keyForList: dateType,
isSelected: config?.exportDate === dateType,
isSelected: selectedValue === dateType,
}));

const headerContent = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ import useThemeStyles from '@hooks/useThemeStyles';
import * as Connections from '@libs/actions/connections/NetSuiteCommands';
import * as ErrorUtils from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
import {canUseProvincialTaxNetSuite, canUseTaxNetSuite} from '@libs/PolicyUtils';
import {
canUseProvincialTaxNetSuite,
canUseTaxNetSuite,
findSelectedBankAccountWithDefaultSelect,
findSelectedInvoiceItemWithDefaultSelect,
findSelectedTaxAccountWithDefaultSelect,
} from '@libs/PolicyUtils';
import type {DividerLineItem, MenuItem, ToggleItem} from '@pages/workspace/accounting/netsuite/types';
import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
import withPolicyConnections from '@pages/workspace/withPolicyConnections';
Expand All @@ -30,13 +36,13 @@ function NetSuiteExportConfigurationPage({policy}: WithPolicyConnectionsProps) {
const {subsidiaryList, receivableList, taxAccountsList, items} = policy?.connections?.netsuite?.options?.data ?? {};
const selectedSubsidiary = useMemo(() => (subsidiaryList ?? []).find((subsidiary) => subsidiary.internalID === config?.subsidiaryID), [subsidiaryList, config?.subsidiaryID]);

const selectedReceivable = useMemo(() => (receivableList ?? []).find((receivable) => receivable.id === config?.receivableAccount), [receivableList, config?.receivableAccount]);
const selectedReceivable = useMemo(() => findSelectedBankAccountWithDefaultSelect(receivableList, config?.receivableAccount), [receivableList, config?.receivableAccount]);

const selectedItem = useMemo(() => (items ?? []).find((item) => item.id === config?.invoiceItem), [items, config?.invoiceItem]);
const selectedItem = useMemo(() => findSelectedInvoiceItemWithDefaultSelect(items, config?.invoiceItem), [items, config?.invoiceItem]);

const invoiceItemValue = useMemo(() => {
if (!config?.invoiceItemPreference) {
return undefined;
return translate('workspace.netsuite.invoiceItem.values.create.label');
}
if (config.invoiceItemPreference === CONST.NETSUITE_INVOICE_ITEM_PREFERENCE.CREATE) {
return translate('workspace.netsuite.invoiceItem.values.create.label');
Expand All @@ -47,13 +53,10 @@ function NetSuiteExportConfigurationPage({policy}: WithPolicyConnectionsProps) {
return selectedItem.name;
}, [config?.invoiceItemPreference, selectedItem, translate]);

const selectedTaxPostingAccount = useMemo(
() => (taxAccountsList ?? []).find((taxAccount) => taxAccount.externalID === config?.taxPostingAccount),
[taxAccountsList, config?.taxPostingAccount],
);
const selectedTaxPostingAccount = useMemo(() => findSelectedTaxAccountWithDefaultSelect(taxAccountsList, config?.taxPostingAccount), [taxAccountsList, config?.taxPostingAccount]);

const selectedProvTaxPostingAccount = useMemo(
() => (taxAccountsList ?? []).find((taxAccount) => taxAccount.externalID === config?.provincialTaxPostingAccount),
() => findSelectedTaxAccountWithDefaultSelect(taxAccountsList, config?.provincialTaxPostingAccount),
[taxAccountsList, config?.provincialTaxPostingAccount],
);

Expand All @@ -79,7 +82,9 @@ function NetSuiteExportConfigurationPage({policy}: WithPolicyConnectionsProps) {
description: translate('workspace.accounting.exportDate'),
onPress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_DATE_SELECT.getRoute(policyID)),
brickRoadIndicator: config?.errorFields?.exportDate ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
title: config?.exportDate ? translate(`workspace.netsuite.exportDate.values.${config.exportDate}.label`) : undefined,
title: config?.exportDate
? translate(`workspace.netsuite.exportDate.values.${config.exportDate}.label`)
: translate(`workspace.netsuite.exportDate.values.${CONST.NETSUITE_EXPORT_DATE.LAST_EXPENSE}.label`),
pendingAction: config?.pendingFields?.exportDate,
errors: ErrorUtils.getLatestErrorField(config, CONST.NETSUITE_CONFIG.EXPORT_DATE),
onCloseError: () => Policy.clearNetSuiteErrorField(policyID, CONST.NETSUITE_CONFIG.EXPORT_DATE),
Expand Down
Loading

0 comments on commit 67493ab

Please sign in to comment.