Skip to content

Commit

Permalink
Merge pull request #43661 from software-mansion-labs/@szymczak/connec…
Browse files Browse the repository at this point in the history
…t-to-sage-intacct

Connect to sage intacct
  • Loading branch information
yuwenmemon authored Jun 28, 2024
2 parents 76e96b9 + a84a85d commit 1f9b4e0
Show file tree
Hide file tree
Showing 32 changed files with 924 additions and 38 deletions.
216 changes: 216 additions & 0 deletions assets/images/computer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions assets/images/integrationicons/sage-intacct-icon-square.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,9 @@ const CONST = {
ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/',
LIST_OF_RESTRICTED_BUSINESSES: 'https://community.expensify.com/discussion/6191/list-of-restricted-businesses',
TRAVEL_TERMS_URL: `${USE_EXPENSIFY_URL}/travelterms`,
EXPENSIFY_PACKAGE_FOR_SAGE_INTACCT: 'https://www.expensify.com/tools/integrations/downloadPackage',
EXPENSIFY_PACKAGE_FOR_SAGE_INTACCT_FILE_NAME: 'ExpensifyPackageForSageIntacct',
HOW_TO_CONNECT_TO_SAGE_INTACCT: 'https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct#how-to-connect-to-sage-intacct',
PRICING: `https://www.expensify.com/pricing`,

// Use Environment.getEnvironmentURL to get the complete URL with port number
Expand Down Expand Up @@ -1793,11 +1796,13 @@ const CONST = {
QBO: 'quickbooksOnline',
XERO: 'xero',
NETSUITE: 'netsuite',
SAGE_INTACCT: 'intacct',
},
NAME_USER_FRIENDLY: {
netsuite: 'NetSuite',
quickbooksOnline: 'Quickbooks Online',
xero: 'Xero',
intacct: 'Sage Intacct',
},
SYNC_STAGE_NAME: {
STARTING_IMPORT_QBO: 'startingImportQBO',
Expand Down Expand Up @@ -1846,9 +1851,10 @@ const CONST = {
NETSUITE_SYNC_NETSUITE_REIMBURSED_REPORTS: 'netSuiteSyncNetSuiteReimbursedReports',
NETSUITE_SYNC_EXPENSIFY_REIMBURSED_REPORTS: 'netSuiteSyncExpensifyReimbursedReports',
SAGE_INTACCT_SYNC_CHECK_CONNECTION: 'intacctCheckConnection',
SAGE_INTACCT_SYNC_IMPORT_TITLE: 'intacctImportTitle',
SAGE_INTACCT_SYNC_IMPORT_DATA: 'intacctImportData',
SAGE_INTACCT_SYNC_IMPORT_DIMENSIONS: 'intacctImportDimensions',
SAGE_INTACCT_SYNC_IMPORT_EMPLOYEES: 'intacctImportEmployees',
SAGE_INTACCT_SYNC_IMPORT_DIMENSIONS: 'intacctImportDimensions',
SAGE_INTACCT_SYNC_IMPORT_SYNC_REIMBURSED_REPORTS: 'intacctImportSyncBillPayments',
},
SYNC_STAGE_TIMEOUT_MINUTES: 20,
Expand Down
3 changes: 3 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@ const ONYXKEYS = {
SUBSCRIPTION_SIZE_FORM_DRAFT: 'subscriptionSizeFormDraft',
ISSUE_NEW_EXPENSIFY_CARD_FORM: 'issueNewExpensifyCardForm',
ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT: 'issueNewExpensifyCardFormDraft',
SAGE_INTACCT_CREDENTIALS_FORM: 'sageIntacctCredentialsForm',
SAGE_INTACCT_CREDENTIALS_FORM_DRAFT: 'sageIntacctCredentialsFormDraft',
},
} as const;

Expand Down Expand Up @@ -587,6 +589,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.NEW_CHAT_NAME_FORM]: FormTypes.NewChatNameForm;
[ONYXKEYS.FORMS.SUBSCRIPTION_SIZE_FORM]: FormTypes.SubscriptionSizeForm;
[ONYXKEYS.FORMS.ISSUE_NEW_EXPENSIFY_CARD_FORM]: FormTypes.IssueNewExpensifyCardForm;
[ONYXKEYS.FORMS.SAGE_INTACCT_CREDENTIALS_FORM]: FormTypes.SageIntactCredentialsForm;
};

type OnyxFormDraftValuesMapping = {
Expand Down
12 changes: 12 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,18 @@ const ROUTES = {
route: 'restricted-action/workspace/:policyID',
getRoute: (policyID: string) => `restricted-action/workspace/${policyID}` as const,
},
POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES: {
route: 'settings/workspaces/:policyID/accounting/sage-intacct/prerequisites',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/prerequisites` as const,
},
POLICY_ACCOUNTING_SAGE_INTACCT_ENTER_CREDENTIALS: {
route: 'settings/workspaces/:policyID/accounting/sage-intacct/enter-credentials',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/enter-credentials` as const,
},
POLICY_ACCOUNTING_SAGE_INTACCT_EXISTING_CONNECTIONS: {
route: 'settings/workspaces/:policyID/accounting/sage-intacct/existing-connections',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/existing-connections` as const,
},
} as const;

/**
Expand Down
3 changes: 3 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,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_SUBSIDIARY_SELECTOR: 'Policy_Accounting_Net_Suite_Subsidiary_Selector',
SAGE_INTACCT_PREREQUISITES: 'Policy_Accounting_Sage_Intacct_Prerequisites',
ENTER_SAGE_INTACCT_CREDENTIALS: 'Policy_Enter_Sage_Intacct_Credentials',
EXISTING_SAGE_INTACCT_CONNECTIONS: 'Policy_Existing_Sage_Intacct_Connections',
},
INITIAL: 'Workspace_Initial',
PROFILE: 'Workspace_Profile',
Expand Down
128 changes: 128 additions & 0 deletions src/components/ConnectToSageIntacctButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, {useRef, useState} from 'react';
import type {View} from 'react-native';
import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal';
import Button from '@components/Button';
import * as Expensicons from '@components/Icon/Expensicons';
import PopoverMenu from '@components/PopoverMenu';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {removePolicyConnection} from '@libs/actions/connections';
import {getPoliciesConnectedToSageIntacct} from '@libs/actions/Policy/Policy';
import Navigation from '@libs/Navigation/Navigation';
import type {AnchorPosition} from '@styles/index';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {PolicyConnectionName} from '@src/types/onyx/Policy';

type ConnectToSageIntacctButtonProps = {
policyID: string;
shouldDisconnectIntegrationBeforeConnecting?: boolean;
integrationToDisconnect?: PolicyConnectionName;
};

function ConnectToSageIntacctButton({policyID, shouldDisconnectIntegrationBeforeConnecting, integrationToDisconnect}: ConnectToSageIntacctButtonProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isOffline} = useNetwork();

const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false);

const hasPoliciesConnectedToSageIntacct = !!getPoliciesConnectedToSageIntacct().length;
const {isSmallScreenWidth} = useWindowDimensions();
const [isReuseConnectionsPopoverOpen, setIsReuseConnectionsPopoverOpen] = useState(false);
const [reuseConnectionPopoverPosition, setReuseConnectionPopoverPosition] = useState<AnchorPosition>({horizontal: 0, vertical: 0});
const threeDotsMenuContainerRef = useRef<View>(null);
const connectionOptions = [
{
icon: Expensicons.LinkCopy,
text: translate('workspace.intacct.createNewConnection'),
onSelected: () => {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES.getRoute(policyID));
setIsReuseConnectionsPopoverOpen(false);
},
},
{
icon: Expensicons.Copy,
text: translate('workspace.intacct.reuseExistingConnection'),
onSelected: () => {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_EXISTING_CONNECTIONS.getRoute(policyID));
setIsReuseConnectionsPopoverOpen(false);
},
},
];

return (
<>
<Button
onPress={() => {
if (shouldDisconnectIntegrationBeforeConnecting && integrationToDisconnect) {
setIsDisconnectModalOpen(true);
return;
}
if (!hasPoliciesConnectedToSageIntacct) {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES.getRoute(policyID));
return;
}
if (!isSmallScreenWidth) {
threeDotsMenuContainerRef.current?.measureInWindow((x, y, width, height) => {
setReuseConnectionPopoverPosition({
horizontal: x + width,
vertical: y + height,
});
});
}
setIsReuseConnectionsPopoverOpen(true);
}}
text={translate('workspace.accounting.setup')}
style={styles.justifyContentCenter}
small
isDisabled={isOffline}
ref={threeDotsMenuContainerRef}
/>
<PopoverMenu
isVisible={isReuseConnectionsPopoverOpen}
onClose={() => {
setIsReuseConnectionsPopoverOpen(false);
}}
withoutOverlay
menuItems={connectionOptions}
onItemSelected={(item) => {
if (!item?.onSelected) {
return;
}
item.onSelected();
}}
anchorPosition={reuseConnectionPopoverPosition}
anchorAlignment={{horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP}}
anchorRef={threeDotsMenuContainerRef}
/>
{shouldDisconnectIntegrationBeforeConnecting && isDisconnectModalOpen && integrationToDisconnect && (
<AccountingConnectionConfirmationModal
onConfirm={() => {
removePolicyConnection(policyID, integrationToDisconnect);
setIsDisconnectModalOpen(false);
if (!hasPoliciesConnectedToSageIntacct) {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES.getRoute(policyID));
return;
}
if (!isSmallScreenWidth) {
threeDotsMenuContainerRef.current?.measureInWindow((x, y, width, height) => {
setReuseConnectionPopoverPosition({
horizontal: x + width,
vertical: y + height,
});
});
}
setIsReuseConnectionsPopoverOpen(true);
}}
integrationToConnect={CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT}
onCancel={() => setIsDisconnectModalOpen(false)}
/>
)}
</>
);
}

export default ConnectToSageIntacctButton;
2 changes: 2 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import Inbox from '@assets/images/inbox.svg';
import Info from '@assets/images/info.svg';
import NetSuiteSquare from '@assets/images/integrationicons/netsuite-icon-square.svg';
import QBOSquare from '@assets/images/integrationicons/qbo-icon-square.svg';
import SageIntacctSquare from '@assets/images/integrationicons/sage-intacct-icon-square.svg';
import XeroSquare from '@assets/images/integrationicons/xero-icon-square.svg';
import InvoiceGeneric from '@assets/images/invoice-generic.svg';
import Invoice from '@assets/images/invoice.svg';
Expand Down Expand Up @@ -349,6 +350,7 @@ export {
Workflows,
Workspace,
XeroSquare,
SageIntacctSquare as IntacctSquare,
Zoom,
Twitter,
Youtube,
Expand Down
18 changes: 16 additions & 2 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ export default {
shared: 'Shared',
drafts: 'Drafts',
finished: 'Finished',
companyID: 'Company ID',
userID: 'User ID',
disable: 'Disable',
},
location: {
Expand Down Expand Up @@ -2203,6 +2205,17 @@ export default {
noSubsidiariesFound: 'No subsidiaries found',
noSubsidiariesFoundDescription: 'Add the subsidiary in NetSuite and sync the connection again.',
},
intacct: {
sageIntacctSetup: 'Sage Intacct setup',
prerequisitesTitle: 'Before you connect...',
downloadExpensifyPackage: 'Download the Expensify package for Sage Intacct',
followSteps: 'Follow the steps in our How-to: Connect to Sage Intacct instructions',
enterCredentials: 'Enter your Sage Intacct credentials',
createNewConnection: 'Create new connection',
reuseExistingConnection: 'Reuse existing connection',
existingConnections: 'Existing connections',
sageIntacctLastSync: (formattedDate: string) => `Sage Intacct - Last synced ${formattedDate}`,
},
type: {
free: 'Free',
control: 'Control',
Expand Down Expand Up @@ -2462,6 +2475,7 @@ export default {
qbo: 'Quickbooks Online',
xero: 'Xero',
netsuite: 'NetSuite',
intacct: 'Sage Intacct',
setup: 'Connect',
lastSync: 'Last synced just now',
import: 'Import',
Expand Down Expand Up @@ -2608,8 +2622,8 @@ export default {
return 'Marking NetSuite bills and invoices as paid';
case 'intacctCheckConnection':
return 'Checking Sage Intacct connection';
case 'intacctImportDimensions':
return 'Importing dimensions';
case 'intacctImportTitle':
return 'Importing Sage Intacct data';
default: {
return `Translation missing for stage: ${stage}`;
}
Expand Down
16 changes: 16 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ export default {
shared: 'Compartidos',
drafts: 'Borradores',
finished: 'Finalizados',
companyID: 'Empresa ID',
userID: 'Usuario ID',
disable: 'Deshabilitar',
},
connectionComplete: {
Expand Down Expand Up @@ -2236,6 +2238,17 @@ export default {
noSubsidiariesFound: 'No se ha encontrado subsidiarias',
noSubsidiariesFoundDescription: 'Añade la subsidiaria en NetSuite y sincroniza de nuevo la conexión.',
},
intacct: {
sageIntacctSetup: 'Sage Intacct configuración',
prerequisitesTitle: 'Antes de conectar...',
downloadExpensifyPackage: 'Descargar el paquete Expensify para Sage Intacct',
followSteps: 'Siga los pasos de nuestras instrucciones Cómo: Instrucciones para conectarse a Sage Intacct',
enterCredentials: 'Introduzca sus credenciales de Sage Intacct',
createNewConnection: 'Crear una nueva conexión',
reuseExistingConnection: 'Reutilizar la conexión existente',
existingConnections: 'Conexiones existentes',
sageIntacctLastSync: (formattedDate: string) => `Sage Intacct - Última sincronización ${formattedDate}`,
},
type: {
free: 'Gratis',
control: 'Control',
Expand Down Expand Up @@ -2435,6 +2448,7 @@ export default {
qbo: 'Quickbooks Online',
xero: 'Xero',
netsuite: 'NetSuite',
intacct: 'Sage Intacct',
setup: 'Configurar',
lastSync: 'Recién sincronizado',
import: 'Importar',
Expand Down Expand Up @@ -2580,6 +2594,8 @@ export default {
return 'Comprobando la conexión a Sage Intacct';
case 'intacctImportDimensions':
return 'Importando dimensiones';
case 'intacctImportTitle':
return 'Importando datos desde Sage Intacct';
default: {
return `Translation missing for stage: ${stage}`;
}
Expand Down
8 changes: 8 additions & 0 deletions src/libs/API/parameters/ConnectPolicyToSageIntacctParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type ConnectPolicyToSageIntacctParams = {
policyID: string;
intacctCompanyID: string;
intacctUserID: string;
intacctPassword: string;
};

export default ConnectPolicyToSageIntacctParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export type {default as AddMembersToWorkspaceParams} from './AddMembersToWorkspa
export type {default as DeleteMembersFromWorkspaceParams} from './DeleteMembersFromWorkspaceParams';
export type {default as OpenWorkspaceParams} from './OpenWorkspaceParams';
export type {default as OpenWorkspaceViewParams} from './OpenWorkspaceViewParams';
export type {default as ConnectPolicyToSageIntacctParams} from './ConnectPolicyToSageIntacctParams';
export type {default as OpenWorkspaceReimburseViewParams} from './OpenWorkspaceReimburseViewParams';
export type {default as OpenWorkspaceInvitePageParams} from './OpenWorkspaceInvitePageParams';
export type {default as OpenWorkspaceMembersPageParams} from './OpenWorkspaceMembersPageParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ const WRITE_COMMANDS = {
UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY: 'UpdateSubscriptionAddNewUsersAutomatically',
UPDATE_SUBSCRIPTION_SIZE: 'UpdateSubscriptionSize',
UPDATE_NETSUITE_SUBSIDIARY: 'UpdateNetSuiteSubsidiary',
CONNECT_POLICY_TO_SAGE_INTACCT: 'ConnectPolicyToSageIntacct',
} as const;

type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
Expand Down Expand Up @@ -458,6 +459,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams;
[WRITE_COMMANDS.CONNECT_POLICY_TO_SAGE_INTACCT]: Parameters.ConnectPolicyToSageIntacctParams;

// Netsuite parameters
[WRITE_COMMANDS.UPDATE_NETSUITE_SUBSIDIARY]: Parameters.UpdateNetSuiteSubsidiaryParams;
Expand Down
Loading

0 comments on commit 1f9b4e0

Please sign in to comment.