Add Rillet integration multiple account export pages - #95562
Conversation
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running: npx ts-node ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
This reverts commit a4ffa66.
…ltiple-account-export
…stomExportAccountsCount utils
There was a problem hiding this comment.
Two things before this ships:
- The per-card override stores the account code but the backend resolves that NVP as an account id, so exports fail for any card with an override. This one's a blocker since it breaks the main path of the feature.
- The custom account counts and error badges include closed/deactivated cards while the card list filters them out .
🦜 Polyglot Parrot! 🦜Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues: View the translation diffdiff --git a/src/languages/de.ts b/src/languages/de.ts
index 48e73a12fcc..8afcd6c5a2c 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -5623,16 +5623,31 @@ _Für ausführlichere Anweisungen [besuchen Sie unsere Hilfeseite](${CONST.NETSU
exportToMultipleAccounts: 'Export in mehrere Konten konfigurieren',
cardProgramAccount: {
label: 'Kartenprogramm-Konto',
- description: 'Überschreiben Sie das Arbeitsbereichskonto für diese Kartenprogramme.',
- descriptionLevel2: 'Überschreiben Sie das Arbeitsbereichskonto für dieses Kartenprogramm.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Alle Programme verwenden das Standardkonto' : `${customAccountsCount} Programme mit benutzerdefinierten Konten`,
+ description: 'Workspace-Konto für diese Kartenprogramme überschreiben.',
+ descriptionLevel2: 'Überschreiben Sie das Workspace-Konto für dieses Kartenprogramm.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Alle Programme verwenden das Standardkonto';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} Programm mit benutzerdefiniertem Konto`;
+ }
+ return `${customAccountsCount} Programme mit benutzerdefinierten Konten`;
+ },
},
cardAccount: {
- label: 'Konto pro Karte',
+ label: 'Kontotyp pro Karte',
description: 'Programmkonto für einzelne Karten überschreiben.',
- descriptionLevel2: 'Programmkonto für diese Karten überschreiben.',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? 'Alle Karten verwenden Programmkonten' : `${customAccountsCount} Karten mit benutzerdefinierten Konten`),
+ descriptionLevel2: 'Programmkonto für diese Karten überschreiben.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Alle Karten verwenden Programmkonten';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} Karte mit individuellem Konto`;
+ }
+ return `${customAccountsCount} Karten mit benutzerdefinierten Konten`;
+ },
},
},
type: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 2a207a96315..ded23f046d7 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -5457,17 +5457,31 @@ ${amount} para ${merchant} - ${date}`,
exportToMultipleAccounts: 'Configura la exportación a varias cuentas',
cardProgramAccount: {
label: 'Cuenta del programa de tarjetas',
- description: 'Sobrescribe la cuenta del espacio de trabajo para estos programas de tarjetas.',
+ description: 'Reemplaza la cuenta del espacio de trabajo para estos programas de tarjetas.',
descriptionLevel2: 'Sobrescribe la cuenta del espacio de trabajo para este programa de tarjetas.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Todos los programas usan la cuenta predeterminada' : `${customAccountsCount} programas con cuentas personalizadas`,
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Todos los programas usan la cuenta predeterminada';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} programa con cuenta personalizada`;
+ }
+ return `${customAccountsCount} programas con cuentas personalizadas`;
+ },
},
cardAccount: {
label: 'Cuenta por tarjeta',
description: 'Sobrescribe la cuenta del programa para tarjetas individuales.',
descriptionLevel2: 'Reemplaza la cuenta del programa para estas tarjetas.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Todas las tarjetas usan cuentas del programa' : `${customAccountsCount} tarjetas con cuentas personalizadas`,
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Todas las tarjetas usan cuentas de programa';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} tarjeta con cuenta personalizada`;
+ }
+ return `${customAccountsCount} tarjetas con cuentas personalizadas`;
+ },
},
},
type: {
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index ddbfba045dd..a777ac091d9 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -5634,20 +5634,34 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST.
label: 'Compte de règlement de facturation de voyage',
description: 'Choisissez votre compte de règlement et nous créerons le paiement dans Rillet.',
},
- exportToMultipleAccounts: 'Configurer l’exportation vers plusieurs comptes',
+ exportToMultipleAccounts: 'Configurer l’export vers plusieurs comptes',
cardProgramAccount: {
- label: 'Compte du programme de carte',
- description: 'Remplacer le compte de l’espace de travail pour ces programmes de carte.',
- descriptionLevel2: 'Remplacer le compte de l’espace de travail pour ce programme de carte.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Tous les programmes utilisent le compte par défaut' : `${customAccountsCount} programmes avec comptes personnalisés`,
+ label: 'Compte de programme de carte',
+ description: 'Remplacer le compte d’espace de travail pour ces programmes de cartes.',
+ descriptionLevel2: 'Remplacer le compte d’espace de travail pour ce programme de carte.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Tous les programmes utilisent le compte par défaut';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} programme avec compte personnalisé`;
+ }
+ return `${customAccountsCount} programmes avec comptes personnalisés`;
+ },
},
cardAccount: {
label: 'Compte par carte',
description: 'Remplacez le compte de programme pour des cartes individuelles.',
- descriptionLevel2: 'Remplacer le compte du programme pour ces cartes.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Toutes les cartes utilisent des comptes de programme' : `${customAccountsCount} cartes avec comptes personnalisés`,
+ descriptionLevel2: 'Remplacer le compte de programme pour ces cartes.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Toutes les cartes utilisent des comptes de programme';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} carte avec compte personnalisé`;
+ }
+ return `${customAccountsCount} cartes avec comptes personnalisés`;
+ },
},
},
type: {
diff --git a/src/languages/it.ts b/src/languages/it.ts
index de1a42fcdf1..8f0853f2bdb 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -5603,19 +5603,34 @@ _Per istruzioni più dettagliate, [visita il nostro sito di assistenza](${CONST.
settlementAccount: {label: 'Conto di regolamento Carta Expensify', description: 'Scegli il tuo conto di regolamento e creeremo il pagamento in Rillet.'},
syncTravelInvoicingSettlements: 'Sincronizza le liquidazioni di fatturazione viaggi',
travelInvoicingSettlementAccount: {label: 'Conto di regolamento fatturazione viaggi', description: 'Scegli il tuo conto di regolamento e creeremo il pagamento in Rillet.'},
- exportToMultipleAccounts: 'Configura l’esportazione verso più conti',
+ exportToMultipleAccounts: 'Configura l’esportazione su più conti',
cardProgramAccount: {
label: 'Conto del programma carta',
- description: 'Sostituisci il conto della workspace per questi programmi di carte.',
- descriptionLevel2: 'Sostituisci il conto spazio di lavoro per questo programma di carte.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Tutti i programmi usano il conto predefinito' : `${customAccountsCount} programmi con conti personalizzati`,
+ description: 'Sostituisci il conto dell’area di lavoro per questi programmi di carta.',
+ descriptionLevel2: 'Ignora il conto della workspace per questo programma di carte.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Tutti i programmi usano il conto predefinito';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} programma con conto personalizzato`;
+ }
+ return `${customAccountsCount} programmi con conti personalizzati`;
+ },
},
cardAccount: {
label: 'Conto per carta',
- description: 'Sostituisci il conto del programma per le singole carte.',
- descriptionLevel2: 'Sostituisci il conto programma per queste carte.',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? 'Tutte le carte usano conti del programma' : `${customAccountsCount} carte con conti personalizzati`),
+ description: 'Ignora il conto del programma per le singole carte.',
+ descriptionLevel2: 'Ignora il conto del programma per queste carte.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Tutte le carte usano conti di programma';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} carta con conto personalizzato`;
+ }
+ return `${customAccountsCount} carte con conti personalizzati`;
+ },
},
},
type: {
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index aae3a9f7e02..dc294d4c436 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -5543,19 +5543,34 @@ _詳しい手順については、[ヘルプサイトをご覧ください](${CO
settlementAccount: {label: 'Expensify カードの決済口座', description: '精算用の口座を選択すると、Rillet で支払いを作成します。'},
syncTravelInvoicingSettlements: '出張請求の精算を同期',
travelInvoicingSettlementAccount: {label: '出張請求の精算口座', description: '精算用の口座を選択すると、Rillet で支払いを作成します。'},
- exportToMultipleAccounts: '複数の勘定科目へのエクスポートを設定する',
+ exportToMultipleAccounts: '複数アカウントへのエクスポートを設定',
cardProgramAccount: {
label: 'カードプログラム口座',
description: 'これらのカードプログラムのワークスペース口座を上書きします。',
- descriptionLevel2: 'このカードプログラムのワークスペースアカウントを上書きします。',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'すべてのプログラムがデフォルトアカウントを使用します' : `カスタム勘定科目を使用しているプログラムが ${customAccountsCount} 件あります`,
+ descriptionLevel2: 'このカードプログラムのワークスペース口座を上書きします。',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'すべてのプログラムがデフォルトアカウントを使用します';
+ }
+ if (customAccountsCount === 1) {
+ return `カスタム勘定科目付きプログラム:${customAccountsCount}`;
+ }
+ return `${customAccountsCount} 件のカスタムアカウントを含むプログラム`;
+ },
},
cardAccount: {
- label: 'カード単位の口座',
- description: '個々のカードのプログラム口座を上書きします。',
+ label: 'カード単位のアカウント',
+ description: '個々のカードに対してプログラム口座を上書きします。',
descriptionLevel2: 'これらのカードのプログラム口座を上書きします。',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? 'すべてのカードはプログラムアカウントを使用します' : `カスタム口座付きカード ${customAccountsCount} 枚`),
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'すべてのカードはプログラムアカウントを使用します';
+ }
+ if (customAccountsCount === 1) {
+ return `カスタム口座のカードが ${customAccountsCount} 枚`;
+ }
+ return `${customAccountsCount} 枚のカスタムアカウント付きカード`;
+ },
},
},
type: {
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index b81effffd28..88a1f2b5ded 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -5593,19 +5593,34 @@ _Voor meer gedetailleerde instructies, [bezoek onze help-site](${CONST.NETSUITE_
label: 'Rekening voor verrekening van reiskostenfacturen',
description: 'Kies je vereffeningsrekening en we maken de betaling voor je aan in Rillet.',
},
- exportToMultipleAccounts: 'Instellen van exporteren naar meerdere rekeningen',
+ exportToMultipleAccounts: 'Export naar meerdere rekeningen instellen',
cardProgramAccount: {
label: 'Kaartprogramma-account',
- description: 'Overschrijf de werkruimte-account voor deze kaartprogramma’s.',
- descriptionLevel2: 'Overschrijf de werkruimte-account voor dit kaartprogramma.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Alle programma’s gebruiken de standaardrekening' : `${customAccountsCount} programma’s met aangepaste accounts`,
+ description: "Overschrijf de werkruimte-account voor deze kaartprogramma's.",
+ descriptionLevel2: 'Overschrijf het werkruimteaccount voor dit kaartprogramma.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Alle programma’s gebruiken de standaardrekening';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} programma met aangepaste rekening`;
+ }
+ return `${customAccountsCount} programma's met aangepaste rekeningen`;
+ },
},
cardAccount: {
- label: 'Rekening per kaart',
+ label: 'Account per kaart',
description: 'Overschrijf de programmarekening voor individuele kaarten.',
- descriptionLevel2: 'Overschrijf de programmarekening voor deze kaarten.',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? 'Alle kaarten gebruiken programma-accounts' : `${customAccountsCount} kaarten met aangepaste rekeningen`),
+ descriptionLevel2: 'Stel een andere programmarekening in voor deze kaarten.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Alle kaarten gebruiken programmarekeningen';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} kaart met aangepaste rekening`;
+ }
+ return `${customAccountsCount} kaarten met aangepaste rekeningen`;
+ },
},
},
type: {
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index a8dc386dc11..519c81e012f 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -5580,15 +5580,30 @@ _Aby uzyskać bardziej szczegółowe instrukcje, [odwiedź naszą stronę pomocy
cardProgramAccount: {
label: 'Konto programu kartowego',
description: 'Zastąp konto przestrzeni roboczej dla tych programów kart.',
- descriptionLevel2: 'Nadpisz konto workspace dla tego programu kart.',
- countInfo: (customAccountsCount: number) =>
- !customAccountsCount ? 'Wszystkie programy używają domyślnego konta' : `${customAccountsCount} programy z niestandardowymi kontami`,
+ descriptionLevel2: 'Zastąp konto przestrzeni roboczej dla tego programu kart.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Wszystkie programy używają domyślnego konta';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} program z własnym kontem`;
+ }
+ return `${customAccountsCount} programy z własnymi kontami`;
+ },
},
cardAccount: {
- label: 'Konto przypisane do karty',
- description: 'Zastąp konto programu dla pojedynczych kart.',
- descriptionLevel2: 'Nadpisz konto programu dla tych kart.',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? 'Wszystkie karty używają kont programów' : `${customAccountsCount} karty z kontami niestandardowymi`),
+ label: 'Konto dla każdej karty',
+ description: 'Nadpisz konto programu dla poszczególnych kart.',
+ descriptionLevel2: 'Zastąp konto programu dla tych kart.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Wszystkie karty korzystają z kont programów';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} karta z niestandardowym kontem`;
+ }
+ return `${customAccountsCount} karty z niestandardowymi kontami`;
+ },
},
},
type: {
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 07568e8f49d..e61e7857251 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -5584,18 +5584,34 @@ _Para instruções mais detalhadas, [visite nossa central de ajuda](${CONST.NETS
settlementAccount: {label: 'Conta de liquidação do Cartão Expensify', description: 'Escolha sua conta de liquidação e nós criaremos o pagamento no Rillet.'},
syncTravelInvoicingSettlements: 'Sincronizar liquidações de faturamento de viagens',
travelInvoicingSettlementAccount: {label: 'Conta de liquidação de faturamento de viagem', description: 'Escolha sua conta de liquidação e nós criaremos o pagamento no Rillet.'},
- exportToMultipleAccounts: 'Configurar exportação para múltiplas contas',
+ exportToMultipleAccounts: 'Configurar exportação para várias contas',
cardProgramAccount: {
label: 'Conta do programa de cartão',
- description: 'Substitua a conta do workspace para estes programas de cartão.',
- descriptionLevel2: 'Substituir a conta do espaço de trabalho para este programa de cartão.',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? 'Todos os programas usam a conta padrão' : `${customAccountsCount} programas com contas personalizadas`),
+ description: 'Substitua a conta do espaço de trabalho para esses programas de cartão.',
+ descriptionLevel2: 'Substituir a conta do workspace para este programa de cartão.',
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Todos os programas usam a conta padrão';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} programa com conta personalizada`;
+ }
+ return `${customAccountsCount} programas com contas personalizadas`;
+ },
},
cardAccount: {
label: 'Conta por cartão',
description: 'Substitua a conta do programa para cartões individuais.',
descriptionLevel2: 'Substituir a conta do programa para estes cartões.',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? 'Todos os cartões usam contas de programa' : `${customAccountsCount} cartões com contas personalizadas`),
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return 'Todos os cartões usam contas de programa';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} cartão com conta personalizada`;
+ }
+ return `${customAccountsCount} cartões com contas personalizadas`;
+ },
},
},
type: {
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index c857ab9c486..720e0a8e443 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -5436,15 +5436,31 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM
exportToMultipleAccounts: '配置导出到多个账户',
cardProgramAccount: {
label: '卡计划账户',
- description: '为这些卡片计划覆盖工作区账户。',
+ description: '为这些银行卡计划覆盖工作区账户。',
descriptionLevel2: '为此卡计划覆盖工作区账户。',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? '所有项目使用默认账户' : `${customAccountsCount} 个包含自定义科目的项目`),
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return '所有计划都使用默认账户';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} 个具有自定义账户的计划`;
+ }
+ return `${customAccountsCount} 个带有自定义科目的方案`;
+ },
},
cardAccount: {
label: '按卡计费账户',
- description: '为单张卡片覆盖所属的项目账户。',
+ description: '为单张卡片覆盖默认项目账户。',
descriptionLevel2: '覆盖这些卡片的项目账户。',
- countInfo: (customAccountsCount: number) => (!customAccountsCount ? '所有卡都使用项目账户' : `${customAccountsCount} 张带有自定义账户的卡`),
+ countInfo: (customAccountsCount: number) => {
+ if (!customAccountsCount) {
+ return '所有卡都使用项目账户';
+ }
+ if (customAccountsCount === 1) {
+ return `${customAccountsCount} 张带有自定义账户的卡`;
+ }
+ return `${customAccountsCount} 张带有自定义账户的卡`;
+ },
},
},
type: {
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
|
@s77rt can you please merge main? |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚧 lakchote has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/lakchote in version: 9.4.36-0 🚀
|
|
Deploy Blocker #96413 was identified to be related to this PR. |
|
Deploy Blocker #96414 was identified to be related to this PR. |
|
Deploy Blocker #96415 was identified to be related to this PR. |
|
Deploy Blocker #96417 was identified to be related to this PR. |
|
🚀 Deployed to staging by https://github.com/lakchote in version: 9.4.38-0 🚀
|
|
🚀 Deployed to staging by https://github.com/lakchote in version: 9.4.40-0 🚀
|
|
🚀 Deployed to production by https://github.com/yuwenmemon in version: 9.4.40-0 🚀
Bundle Size Analysis (Sentry): |
Explanation of Change
Added Rillet-integration multiple account export pages
Fixed Issues
$ #94851
PROPOSAL:
Tests
Configure exporting to multiple accountstoggleCard program accountandPer-card accountCard program accountfor each programPer-card accountfor each cardRillet per-card account export)Screen.Recording.2026-07-14.at.9.28.36.PM.mov
Offline tests
Same as Tests
QA Steps
Same as Tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)Avatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari