Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
9862aca
add constants for rillet integration
s77rt Jun 18, 2026
fd60e83
add generic transations for Rillet
s77rt Jun 18, 2026
f0c795b
add Rillet accounting option
s77rt Jun 18, 2026
244a50b
fix displayed upgrade intro
s77rt Jun 18, 2026
767672c
add ConnectToRilletFlow - wip
s77rt Jun 18, 2026
6a501bc
add RilletSetupPage
s77rt Jun 18, 2026
05a35e2
disable rillet form when offline
s77rt Jun 18, 2026
b56a8f3
add RilletExistingConnectionsPage
s77rt Jun 18, 2026
9efb59d
add Rillet connections
s77rt Jun 18, 2026
5890562
add Rillet types
s77rt Jun 18, 2026
39f0056
Merge branch 'main' into Rillet-integration
s77rt Jun 19, 2026
181eeb6
correct screen names
s77rt Jun 19, 2026
f71cd2a
add RilletSubsidiarySelector
s77rt Jun 19, 2026
68d585e
add subsidiary row for Rillet
s77rt Jun 19, 2026
3eaf1b1
add missing reusable connections for rillet
s77rt Jun 19, 2026
b119b35
add updateRilletSubsidiary command
s77rt Jun 19, 2026
a4c3c83
remove useMemo and useCallback from newly added pages
s77rt Jun 19, 2026
6b9fd5a
add subscribtion keys for RBR
s77rt Jun 19, 2026
a8df9e5
add Rillet icon
s77rt Jun 19, 2026
3558b6d
merge main
s77rt Jun 19, 2026
27150f1
compress svg
s77rt Jun 19, 2026
b8edf92
lint
s77rt Jun 19, 2026
b44532c
merge main
s77rt Jun 25, 2026
7f9df8a
use existing style
s77rt Jun 25, 2026
2546ee4
lint
s77rt Jun 25, 2026
f00d8f9
add missed jsdocs
s77rt Jun 25, 2026
cc4a701
add spanish translation
s77rt Jun 25, 2026
a132dd1
lint
s77rt Jun 25, 2026
c852bc7
Revert "add spanish translation"
s77rt Jun 25, 2026
f5cb7ea
translate
s77rt Jun 25, 2026
6b4919a
translate rillet sync stage
s77rt Jun 25, 2026
77f13f7
Merge branch 'main' into Rillet-integration
s77rt Jun 26, 2026
1d68d7e
add rillet sync stages
s77rt Jun 26, 2026
3936bab
translate rillet sync stages
s77rt Jun 26, 2026
9af34fc
use correct friendly name
s77rt Jun 26, 2026
4d3185b
look in errorFields for RBR
s77rt Jun 26, 2026
d001fb7
Revert "translate"
s77rt Jun 26, 2026
10b819d
add comment
s77rt Jun 26, 2026
8c0035d
translate
s77rt Jun 26, 2026
9ab4f2b
add RilletConding offline-feedback keys
s77rt Jun 27, 2026
ff34f88
subscribe to field mappings errors
s77rt Jun 27, 2026
2b52774
add RilletImportPage
s77rt Jun 27, 2026
f7a53f8
use dynamic fields list
s77rt Jun 27, 2026
2913a16
subscribe to dynamic field mappings
s77rt Jun 27, 2026
5c84475
display tex rates sync toggle only if we have tax rates
s77rt Jun 27, 2026
06d1dcc
add prepareRilletOptimisticData helper
s77rt Jun 27, 2026
a506a0c
add updateRilletEnableNewCategories
s77rt Jun 27, 2026
03e0080
better types
s77rt Jun 27, 2026
4c413fe
add updateRilletSyncTaxRates
s77rt Jun 27, 2026
de70b1b
add updateRilletFieldMapping
s77rt Jun 27, 2026
4acce7c
lint
s77rt Jun 27, 2026
2caaa84
add missing key in loop
s77rt Jun 27, 2026
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
1 change: 1 addition & 0 deletions assets/images/integrationicons/rillet-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.
45 changes: 44 additions & 1 deletion src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,7 @@ const CONST = {
CERTINIA: 'financialForceNewDot',
MERGE_HR: 'mergeHRConnections',
VENDOR_MATCHING: 'vendorMatching',
RILLET: 'rillet',
RULES_REVAMP: 'rulesRevamp',
COMMUTER_EXCLUSIONS: 'commuterExclusions',
},
Expand Down Expand Up @@ -3331,6 +3332,34 @@ const CONST = {
VENDOR_BILL: 'VENDOR_BILL',
},

RILLET_CONFIG: {
SUBSIDIARY_ID: 'subsidiaryID',
ENABLE_NEW_CATEGORIES: 'enableNewCategories',
SYNC_TAX_RATES: 'syncTaxRates',
EXPORTER: 'exporter',
EXPORT_DATE: 'exportDate',
REIMBURSABLE: 'reimbursable',
COMPANY_CARD: 'companyCard',
DEFAULT_VENDORID: 'defaultVendorID',
CREDIT_CARD_ACCOUNTCODE: 'creditCardAccountCode',
EXPORT_TO_MULTIPLE_ACCOUNTS: 'exportToMultipleAccounts',
CARD_PROGRAM_ACCOUNTS: 'cardProgramAccounts',
ACCOUNTING_METHOD: 'accountingMethod',
AUTO_SYNC: 'autoSync',
SYNC_REIMBURSED_REPORTS: 'syncReimbursedReports',
BILL_PAYMENT_ACCOUNT_CODE: 'billPaymentAccountCode',
SYNC_EXPENSIFY_CARD_SETTLEMENTS: 'syncExpensifyCardSettlements',
SETTLEMENTS_BANK_ACCOUNT_ID: 'settlementsBankAccountID',
SYNC_TRAVEL_INVOICING_SETTLEMENTS: 'syncTravelInvoicingSettlements',
TRAVEL_INVOICING_SETTLEMENTS_BANK_ACCOUNT_ID: 'travelInvoicingSettlementsBankAccountID',
FIELD_MAPPING_PREFIX: 'fieldMapping_',
},

RILLET_MAPPING_VALUE: {
NONE: 'NONE',
TAG: 'TAG',
},

UPDATE_PERSONAL_BANK_ACCOUNT: {
PAGE_NAME: {
LEGAL_NAME: 'legal-name',
Expand Down Expand Up @@ -3986,6 +4015,7 @@ const CONST = {
NETSUITE: 'netsuite',
SAGE_INTACCT: 'intacct',
CERTINIA: 'financialforce',
RILLET: 'rillet',
GUSTO: 'gusto',
ZENEFITS: 'zenefits',
MERGE_HR: 'merge_hris',
Expand All @@ -4003,6 +4033,7 @@ const CONST = {
SAGE_INTACCT: 'sage-intacct',
QBD: 'quickbooks-desktop',
CERTINIA: 'certinia',
RILLET: 'rillet',
GUSTO: 'gusto',
ZENEFITS: 'zenefits',
MERGE_HR: 'merge-hr',
Expand All @@ -4014,6 +4045,7 @@ const CONST = {
xero: 'Xero',
intacct: 'Sage Intacct',
financialforce: 'Certinia',
rillet: 'Rillet',
gusto: 'Gusto',
billCom: 'Bill.com',
zenefits: 'TriNet',
Expand All @@ -4024,7 +4056,7 @@ const CONST = {
other: 'Other',
},
get ACCOUNTING_CONNECTION_NAMES() {
return [this.NAME.QBO, this.NAME.QBD, this.NAME.XERO, this.NAME.NETSUITE, this.NAME.SAGE_INTACCT, this.NAME.CERTINIA] as const;
return [this.NAME.QBO, this.NAME.QBD, this.NAME.XERO, this.NAME.NETSUITE, this.NAME.SAGE_INTACCT, this.NAME.CERTINIA, this.NAME.RILLET] as const;
},
get HR_CONNECTION_NAMES() {
return [this.NAME.GUSTO, this.NAME.ZENEFITS, this.NAME.MERGE_HR] as const;
Expand Down Expand Up @@ -4124,6 +4156,9 @@ const CONST = {
FINANCIAL_FORCE_SYNC_USERS: 'financialForceSyncUsers',
FINANCIAL_FORCE_SYNC_DIMENSIONS: 'financialForceSyncDimensions',
FINANCIAL_FORCE_SYNC_MARK_REIMBURSED: 'financialForceMarkAsReimbursed',
RILLET_SYNC_TITLE: 'rilletSyncTitle',
RILLET_SYNC_CONNECTION: 'rilletSyncConnection',
RILLET_SYNC_IMPORT_DATA: 'rilletSyncImportData',
},
SYNC_STAGE_TIMEOUT_MINUTES: 20,
},
Expand Down Expand Up @@ -7209,6 +7244,14 @@ const CONST = {
description: `workspace.upgrade.${this.POLICY.CONNECTIONS.NAME.CERTINIA}.description` as const,
icon: 'CertiniaSquare',
},
[this.POLICY.CONNECTIONS.NAME.RILLET]: {
id: this.POLICY.CONNECTIONS.NAME.RILLET,
alias: 'rillet',
name: this.POLICY.CONNECTIONS.NAME_USER_FRIENDLY.rillet,
title: `workspace.upgrade.${this.POLICY.CONNECTIONS.NAME.RILLET}.title` as const,
description: `workspace.upgrade.${this.POLICY.CONNECTIONS.NAME.RILLET}.description` as const,
icon: 'RilletSquare',
},
approvals: {
id: 'approvals' as const,
alias: 'approvals' as const,
Expand Down
3 changes: 3 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,8 @@ const ONYXKEYS = {
ADD_AGENT_RULE_FORM_DRAFT: 'addAgentRuleFormDraft',
EDIT_AGENT_RULE_FORM: 'editAgentRuleForm',
EDIT_AGENT_RULE_FORM_DRAFT: 'editAgentRuleFormDraft',
RILLET_CREDENTIALS_FORM: 'rilletCredentialsForm',
RILLET_CREDENTIALS_FORM_DRAFT: 'rilletCredentialsFormDraft',
},
DERIVED: {
REPORT_ATTRIBUTES: 'reportAttributes',
Expand Down Expand Up @@ -1331,6 +1333,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.EDIT_AGENT_PROMPT_FORM]: FormTypes.EditAgentPromptForm;
[ONYXKEYS.FORMS.ADD_AGENT_RULE_FORM]: FormTypes.AddAgentRuleForm;
[ONYXKEYS.FORMS.EDIT_AGENT_RULE_FORM]: FormTypes.EditAgentRuleForm;
[ONYXKEYS.FORMS.RILLET_CREDENTIALS_FORM]: FormTypes.RilletCredentialsForm;
};

type OnyxFormDraftValuesMapping = {
Expand Down
16 changes: 16 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3994,6 +3994,22 @@ const ROUTES = {
return `workspaces/${policyID}/accounting/certinia/company` as const;
},
},
POLICY_ACCOUNTING_RILLET_SETUP: {
route: 'workspaces/:policyID/accounting/rillet/setup',
getRoute: (policyID: string) => `workspaces/${policyID}/accounting/rillet/setup` as const,
},
POLICY_ACCOUNTING_RILLET_EXISTING_CONNECTIONS: {
route: 'workspaces/:policyID/accounting/rillet/existing-connections',
getRoute: (policyID: string) => `workspaces/${policyID}/accounting/rillet/existing-connections` as const,
},
POLICY_ACCOUNTING_RILLET_SUBSIDIARY_SELECTOR: {
route: 'workspaces/:policyID/accounting/rillet/subsidiary-selector',
getRoute: (policyID: string) => `workspaces/${policyID}/accounting/rillet/subsidiary-selector` as const,
},
POLICY_ACCOUNTING_RILLET_IMPORT: {
route: 'workspaces/:policyID/accounting/rillet/import',
getRoute: (policyID: string) => `workspaces/${policyID}/accounting/rillet/import` as const,
},
ADD_EXISTING_EXPENSE: {
route: 'search/r/:reportID/add-existing-expense/:backToReport?',
getRoute: (reportID: string | undefined, backToReport?: string) => `search/r/${reportID}/add-existing-expense/${backToReport ?? ''}` as const,
Expand Down
4 changes: 4 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,10 @@ const SCREENS = {
CERTINIA_TAGS_MAPPING: 'Policy_Accounting_Certinia_Tags_Mapping',
CERTINIA_REPORT_EXPORT_STATUS: 'Policy_Accounting_Certinia_Report_Export_Status',
CERTINIA_COMPANY_SELECTOR: 'Policy_Accounting_Certinia_Company_Selector',
RILLET_SETUP: 'Policy_Accounting_Rillet_Setup',
RILLET_EXISTING_CONNECTIONS: 'Policy_Accounting_Rillet_Existing_Connections',
RILLET_SUBSIDIARY_SELECTOR: 'Policy_Accounting_Rillet_Subsidiary_Selector',
RILLET_IMPORT: 'Policy_Accounting_Rillet_Import',
CARD_RECONCILIATION: 'Policy_Accounting_Card_Reconciliation',
CARD_RECONCILIATION_SAGE_INTACCT_AUTO_SYNC: 'Policy_Accounting_Card_Reconciliation_Sage_Intacct_Auto_Sync',
DYNAMIC_RECONCILIATION_ACCOUNT_SETTINGS: 'Dynamic_Policy_Accounting_Reconciliation_Account_Settings',
Expand Down
27 changes: 27 additions & 0 deletions src/components/ConnectToRilletFlow/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {useEffect} from 'react';
import useHasReusablePoliciesConnectedTo from '@hooks/useHasReusablePoliciesConnectedTo';
import Navigation from '@libs/Navigation/Navigation';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';

type ConnectToRilletFlowProps = {
policyID: string;
};

function ConnectToRilletFlow({policyID}: ConnectToRilletFlowProps) {
const hasReusablePoliciesConnectedToRillet = useHasReusablePoliciesConnectedTo(CONST.POLICY.CONNECTIONS.NAME.RILLET, policyID);

useEffect(() => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ PERF-16 (docs)

This useEffect has an empty dependency array and performs Navigation.navigate(...), which is non-idempotent. React Strict Mode intentionally double-invokes effects in development, so this effect can fire two navigations on mount. There is no guard (module-level flag or ref) preventing the second run — the if (hasReusablePoliciesConnectedToRillet) check validates a precondition but does not stop re-execution if the same precondition still holds on the second invocation.

Guard the one-time initialization so it runs exactly once regardless of rendering mode:

const didInit = useRef(false);

useEffect(() => {
    if (didInit.current) {
        return;
    }
    didInit.current = true;

    if (hasReusablePoliciesConnectedToRillet) {
        Navigation.navigate(ROUTES.POLICY_ACCOUNTING_RILLET_EXISTING_CONNECTIONS.getRoute(policyID));
        return;
    }
    Navigation.navigate(ROUTES.POLICY_ACCOUNTING_RILLET_SETUP.getRoute(policyID));
    // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Reviewed at: 2caaa84 | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

if (hasReusablePoliciesConnectedToRillet) {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_RILLET_EXISTING_CONNECTIONS.getRoute(policyID));
return;
}
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_RILLET_SETUP.getRoute(policyID));
// This needs to run once as we will navigate away
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return null;
}

export default ConnectToRilletFlow;
2 changes: 2 additions & 0 deletions src/components/Icon/chunks/expensify-icons.chunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ import OracleSquare from '@assets/images/integrationicons/oracle-icon-square.svg
import QBDSquare from '@assets/images/integrationicons/qbd-icon-square.svg';
import QBOCircle from '@assets/images/integrationicons/qbo-icon-circle.svg';
import QBOSquare from '@assets/images/integrationicons/qbo-icon-square.svg';
import RilletSquare from '@assets/images/integrationicons/rillet-icon-square.svg';
import SageIntacctSquare from '@assets/images/integrationicons/sage-intacct-icon-square.svg';
import SapSquare from '@assets/images/integrationicons/sap-icon-square.svg';
import TriNetSquare from '@assets/images/integrationicons/trinet-icon-square.svg';
Expand Down Expand Up @@ -465,6 +466,7 @@ const Expensicons = {
ReportCopy,
ReplaceReceipt,
ReceiptMultiple,
RilletSquare,
Rotate,
RotateLeft,
Scan,
Expand Down
2 changes: 1 addition & 1 deletion src/components/ImportedFromAccountingSoftware.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function ImportedFromAccountingSoftware({policyID, currentConnectionName, transl
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const {environmentURL} = useEnvironment();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['XeroSquare', 'QBOSquare', 'NetSuiteSquare', 'IntacctSquare', 'QBDSquare', 'CertiniaSquare', 'GustoSquare']);
const expensifyIcons = useMemoizedLazyExpensifyIcons(['XeroSquare', 'QBOSquare', 'NetSuiteSquare', 'IntacctSquare', 'QBDSquare', 'CertiniaSquare', 'RilletSquare', 'GustoSquare']);
const icon = getIntegrationIcon(connectedIntegration, expensifyIcons);

if (!customTagName && shouldShow) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function ExportWithDropdownMenu({
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {showConfirmModal} = useConfirmModal();
const [exportMethods] = useOnyx(ONYXKEYS.LAST_EXPORT_METHOD);
const expensifyIcons = useMemoizedLazyExpensifyIcons(['XeroSquare', 'QBOSquare', 'NetSuiteSquare', 'IntacctSquare', 'QBDSquare', 'CertiniaSquare', 'GustoSquare']);
const expensifyIcons = useMemoizedLazyExpensifyIcons(['XeroSquare', 'QBOSquare', 'NetSuiteSquare', 'IntacctSquare', 'QBDSquare', 'CertiniaSquare', 'RilletSquare', 'GustoSquare']);

const iconToDisplay = getIntegrationIcon(connectionName, expensifyIcons);
const canBeExported = canBeExportedUtils(report);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function ExportedToSelector({value = [], policyIDs = [], selectionListTextInputS
'IntacctSquare',
'QBDSquare',
'CertiniaSquare',
'RilletSquare',
'GustoSquare',
'Table',
'TablePencil',
Expand Down
1 change: 1 addition & 0 deletions src/hooks/useExportActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ function useExportActions({reportID, policy, onPDFModalOpen}: UseExportActionsPa
'IntacctSquare',
'QBDSquare',
'CertiniaSquare',
'RilletSquare',
'GustoSquare',
'ArrowRight',
]);
Expand Down
1 change: 1 addition & 0 deletions src/hooks/useSearchBulkActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
'IntacctSquare',
'QBDSquare',
'CertiniaSquare',
'RilletSquare',
'GustoSquare',
'Pencil',
'Workflows',
Expand Down
26 changes: 26 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@
editor: 'Editor',
restrictions: 'Beschränkungen',
off: 'Aus',
apiKey: 'API-Schlüssel',
},
socials: {
podcast: 'Folgen Sie uns auf Podcast',
Expand Down Expand Up @@ -5486,6 +5487,16 @@
}
},
},
rillet: {

Check failure on line 5490 in src/languages/de.ts

View workflow job for this annotation

GitHub Actions / typecheck

Type '{ rilletSetup: string; enterCredentials: string; howToFindAPIKey: string; subsidiary: string; subsidiarySelectDescription: string; noSubsidiariesFound: string; noSubsidiariesFoundDescription: string; }' is missing the following properties from type 'TranslationDeepObject<{ rilletSetup: string; enterCredentials: string; howToFindAPIKey: string; subsidiary: string; subsidiarySelectDescription: string; noSubsidiariesFound: string; noSubsidiariesFoundDescription: string; accountTypesDescription: string; enableNewAccountsTitle: string; enableNewAccountsDescription: ...': accountTypesDescription, enableNewAccountsTitle, enableNewAccountsDescription, dimensionsImport
rilletSetup: 'Rillet-Einrichtung',
enterCredentials: 'Geben Sie Ihren Rillet-API-Schlüssel ein',
howToFindAPIKey:
'<strong>So finden Sie Ihren API-Schlüssel.</strong><ol><li>Melden Sie sich bei Rillet an</li><li>Navigieren Sie zu Konto -> Einstellungen</li><li>Kopieren Sie den unten stehenden API-Schlüssel</li></ol>',
subsidiary: 'Tochtergesellschaft',
subsidiarySelectDescription: 'Wählen Sie die Tochtergesellschaft in Rillet aus, aus der Sie Daten importieren möchten.',
noSubsidiariesFound: 'Keine Tochtergesellschaften gefunden',
noSubsidiariesFoundDescription: 'Bitte fügen Sie eine Tochtergesellschaft in Rillet hinzu und synchronisieren Sie die Verbindung erneut.',
},
type: {
free: 'Kostenlos',
control: 'Steuerung',
Expand Down Expand Up @@ -6205,7 +6216,7 @@
other: (count: number) => `${count} Tags`,
}),
},
taxes: {

Check failure on line 6219 in src/languages/de.ts

View workflow job for this annotation

GitHub Actions / typecheck

Property 'taxRates' is missing in type '{ subtitle: string; addRate: string; workspaceDefault: string; foreignDefault: string; customTaxName: string; value: string; taxReclaimableOn: string; taxRate: string; findTaxRate: string; error: { ...; }; ... 5 more ...; updateTaxCodeFailureMessage: string; }' but required in type 'TranslationDeepObject<{ subtitle: string; addRate: string; workspaceDefault: string; foreignDefault: string; customTaxName: string; value: string; taxReclaimableOn: string; taxRate: string; taxRates: string; findTaxRate: string; ... 6 more ...; updateTaxCodeFailureMessage: string; }>'.
subtitle: 'Steuernamen und -sätze hinzufügen und Standardwerte festlegen.',
addRate: 'Satz hinzufügen',
workspaceDefault: 'Standardwährung des Workspaces',
Expand Down Expand Up @@ -6452,6 +6463,7 @@
xero: 'Xero',
netsuite: 'NetSuite',
intacct: 'Sage Intacct',
rillet: 'Rillet',
sap: 'SAP',
oracle: 'Oracle',
microsoftDynamics: 'Microsoft Dynamics',
Expand All @@ -6469,6 +6481,8 @@
return 'NetSuite';
case CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT:
return 'Sage Intacct';
case CONST.POLICY.CONNECTIONS.NAME.RILLET:
return 'Rillet';
default: {
return '';
}
Expand Down Expand Up @@ -6694,6 +6708,12 @@
return 'Dimensionen werden importiert';
case 'financialForceMarkAsReimbursed':
return 'Berichte werden als erstattet markiert';
case 'rilletSyncTitle':
return 'Rillet-Daten werden synchronisiert';
case 'rilletSyncConnection':
return 'Verbindung mit Rillet wird initialisiert';
case 'rilletSyncImportData':
return 'Daten werden geladen';
default: {
return `Übersetzung fehlt für Stufe: ${stage}`;
}
Expand Down Expand Up @@ -6964,6 +6984,12 @@
onlyAvailableOnPlan: ({formattedPrice, hasTeam2025Pricing}: {formattedPrice: string; hasTeam2025Pricing: boolean}) =>
`<muted-text>Unsere Certinia-Integration ist nur im Control-Tarif verfügbar, beginnend bei <strong>${formattedPrice}</strong> ${hasTeam2025Pricing ? `pro Mitglied und Monat.` : `pro aktivem Mitglied und Monat.`}</muted-text>`,
},
[CONST.POLICY.CONNECTIONS.NAME.RILLET]: {
title: 'Rillet',
description: `Profitiere von automatisierter Synchronisierung und reduziere manuelle Eingaben mit der Expensify + Rillet-Integration. Richte Spesenkodierungsdimensionen und die Steuersynchronisierung auf deine Rillet-Einrichtung aus, um eine klarere finanzielle Übersicht zu erhalten.`,
onlyAvailableOnPlan: ({formattedPrice, hasTeam2025Pricing}: {formattedPrice: string; hasTeam2025Pricing: boolean}) =>
`<muted-text>Unsere Rillet-Integration ist nur im Control-Tarif verfügbar, beginnend bei <strong>${formattedPrice}</strong> ${hasTeam2025Pricing ? `pro Mitglied und Monat.` : `pro aktivem Mitglied und Monat.`}</muted-text>`,
},
[CONST.UPGRADE_FEATURE_INTRO_MAPPING.approvals.id]: {
title: 'Erweiterte Genehmigungen',
description: `Wenn du weitere Genehmigungsstufen hinzufügen möchtest – oder einfach sicherstellen willst, dass die höchsten Ausgaben noch einmal geprüft werden – bist du bei uns richtig. Erweiterte Genehmigungen helfen dir, auf jeder Ebene die passenden Kontrollen einzurichten, damit du die Ausgaben deines Teams im Griff behältst.`,
Expand Down
Loading
Loading