From f8573b3d4062cc7f4e0250cb18512b2a461664c6 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Fri, 14 Aug 2026 13:10:38 -0600 Subject: [PATCH 1/4] Show temporary retry-later message for 531 broken card connection Map the new brokenCardConnection531 RTER violation type to its own copy telling the user this is a temporary bank issue to retry later, instead of the generic broken-connection message. --- src/CONST/index.ts | 1 + .../BrokenConnectionDescription.tsx | 7 ++- src/languages/de.ts | 1 + src/languages/el.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/languages/fr.ts | 1 + src/languages/it.ts | 1 + src/languages/ja.ts | 1 + src/languages/nl.ts | 1 + src/languages/pl.ts | 1 + src/languages/pt-BR.ts | 1 + src/languages/zh-hans.ts | 1 + tests/ui/BrokenConnectionDescriptionTest.tsx | 63 +++++++++++++++++++ 14 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/ui/BrokenConnectionDescriptionTest.tsx diff --git a/src/CONST/index.ts b/src/CONST/index.ts index f3f1ce77b402..47293f981aee 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6574,6 +6574,7 @@ const CONST = { RTER_VIOLATION_TYPES: { BROKEN_CARD_CONNECTION: 'brokenCardConnection', BROKEN_CARD_CONNECTION_530: 'brokenCardConnection530', + BROKEN_CARD_CONNECTION_531: 'brokenCardConnection531', SEVEN_DAY_HOLD: 'sevenDayHold', }, REVIEW_DUPLICATES_ORDER: ['merchant', 'category', 'tag', 'description', 'taxCode', 'billable', 'reimbursable'], diff --git a/src/components/BrokenConnectionDescription.tsx b/src/components/BrokenConnectionDescription.tsx index 6699ddc1b190..861e060c6b8f 100644 --- a/src/components/BrokenConnectionDescription.tsx +++ b/src/components/BrokenConnectionDescription.tsx @@ -32,11 +32,12 @@ function BrokenConnectionDescription({transactionID, policy, report}: BrokenConn const {environmentURL} = useEnvironment(); const brokenConnection530Error = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530); + const brokenConnection531Error = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531); const brokenConnectionError = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION); const isPolicyAdmin = isPolicyAdminPolicyUtils(policy); const workspaceCompanyCardRoute = `${environmentURL}/${ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policy?.id)}`; - if (!brokenConnection530Error && !brokenConnectionError) { + if (!brokenConnection530Error && !brokenConnection531Error && !brokenConnectionError) { return ''; } @@ -44,6 +45,10 @@ function BrokenConnectionDescription({transactionID, policy, report}: BrokenConn return translate('violations.brokenConnection530Error'); } + if (brokenConnection531Error) { + return translate('violations.brokenConnection531Error'); + } + if (isPolicyAdmin && !isCurrentUserSubmitter(report)) { return ; } diff --git a/src/languages/de.ts b/src/languages/de.ts index e339cc766d65..27c5dfbd0499 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -9837,6 +9837,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc return ''; }, brokenConnection530Error: 'Beleg ausstehend wegen unterbrochener Bankverbindung', + brokenConnection531Error: 'Beleg ausstehend aufgrund eines vorübergehenden Bankproblems. Bitte versuchen Sie es später erneut.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Beleg ausstehend wegen unterbrochener Bankverbindung. Bitte in Firmenkarten beheben.`, memberBrokenConnectionError: 'Beleg ausstehend aufgrund einer unterbrochenen Bankverbindung. Bitte wende dich an eine Workspace-Admin, um das Problem zu beheben.', diff --git a/src/languages/el.ts b/src/languages/el.ts index eca129a70a5d..37930e7fb8f8 100644 --- a/src/languages/el.ts +++ b/src/languages/el.ts @@ -10068,6 +10068,7 @@ ${reportName}`, return ''; }, brokenConnection530Error: 'Η απόδειξη εκκρεμεί λόγω αποσυνδεδεμένου τραπεζικού λογαριασμού', + brokenConnection531Error: 'Η απόδειξη εκκρεμεί λόγω προσωρινού προβλήματος της τράπεζας. Δοκιμάστε ξανά αργότερα.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Η απόδειξη εκκρεμεί λόγω κατεστραμμένης σύνδεσης τράπεζας. Παρακαλώ επιλύστε το στις εταιρικές κάρτες.`, memberBrokenConnectionError: 'Η απόδειξη εκκρεμεί λόγω προβλήματος στη σύνδεση με την τράπεζα. Παρακαλείστε να ζητήσετε από έναν διαχειριστή χώρου εργασίας να το επιλύσει.', diff --git a/src/languages/en.ts b/src/languages/en.ts index e83404432758..6b80decf849c 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -9981,6 +9981,7 @@ const translations = { return ''; }, brokenConnection530Error: 'Receipt pending due to broken bank connection', + brokenConnection531Error: 'Receipt pending due to a temporary bank issue. Please try again later.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Receipt pending due to broken bank connection. Please resolve in Company cards.`, memberBrokenConnectionError: 'Receipt pending due to broken bank connection. Please ask a workspace admin to resolve.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 8550a36aad84..d89194f7af21 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -10040,6 +10040,7 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`, return ''; }, brokenConnection530Error: 'Recibo pendiente debido a una conexión bancaria rota', + brokenConnection531Error: 'Recibo pendiente debido a un problema temporal del banco. Vuelve a intentarlo más tarde.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}) => `Recibo pendiente debido a una conexión bancaria rota. Por favor, resuélvelo en Tarjetas de empresa.`, memberBrokenConnectionError: 'Recibo pendiente debido a una conexión bancaria rota. Por favor, pide a un administrador del espacio de trabajo que lo resuelva.', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 341f6e276551..27034eae1c38 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -9873,6 +9873,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e return ''; }, brokenConnection530Error: 'Reçu en attente en raison d’une connexion bancaire rompue', + brokenConnection531Error: 'Reçu en attente en raison d’un problème temporaire de la banque. Veuillez réessayer plus tard.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Reçu en attente en raison d’une connexion bancaire rompue. Veuillez résoudre le problème dans les Cartes d’entreprise.`, memberBrokenConnectionError: 'Reçu en attente en raison d’une connexion bancaire rompue. Veuillez demander à un administrateur de l’espace de travail de résoudre le problème.', diff --git a/src/languages/it.ts b/src/languages/it.ts index e5732ddb33a1..23222d87743a 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -9810,6 +9810,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`, return ''; }, brokenConnection530Error: 'Ricevuta in sospeso a causa di connessione bancaria interrotta', + brokenConnection531Error: 'Ricevuta in sospeso a causa di un problema temporaneo della banca. Riprova più tardi.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Ricevuta in sospeso a causa di un collegamento bancario interrotto. Risolvi il problema in Carte aziendali.`, memberBrokenConnectionError: 'Ricevuta in sospeso a causa di un collegamento bancario interrotto. Chiedi a un amministratore dello spazio di lavoro di risolvere il problema.', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 5eaddd3c4e04..7f2133781632 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -9681,6 +9681,7 @@ ${reportName}`, return ''; }, brokenConnection530Error: '銀行連携の不具合により領収書が保留されています', + brokenConnection531Error: '銀行側の一時的な問題により領収書が保留されています。後でもう一度お試しください。', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `銀行接続の不具合により領収書が保留されています。会社カードで解決してください。`, memberBrokenConnectionError: '銀行連携の不具合により領収書が保留されています。ワークスペース管理者に対応を依頼してください。', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 5cfc17a78608..788872ddaae9 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -9780,6 +9780,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`, return ''; }, brokenConnection530Error: 'Bonnetje in behandeling vanwege verbroken bankverbinding', + brokenConnection531Error: 'Bonnetje in behandeling vanwege een tijdelijk probleem bij de bank. Probeer het later opnieuw.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Bon in behandeling vanwege een verbroken bankverbinding. Los dit op in Bedrijfspassen.`, memberBrokenConnectionError: 'Bon wordt vastgehouden vanwege een verbroken bankkoppeling. Vraag een werkruimtebeheerder om dit op te lossen.', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index e3f085645e06..9f7a8df0ec1f 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -9752,6 +9752,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`, return ''; }, brokenConnection530Error: 'Paragon oczekuje z powodu przerwanego połączenia z bankiem', + brokenConnection531Error: 'Paragon oczekuje z powodu tymczasowego problemu z bankiem. Spróbuj ponownie później.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Oczekuje na rachunek z powodu przerwanego połączenia z bankiem. Rozwiąż problem w sekcji Karty firmowe.`, memberBrokenConnectionError: 'Paragon oczekuje z powodu zerwanego połączenia z bankiem. Poproś administratora przestrzeni roboczej o rozwiązanie problemu.', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 1fc515162525..85e2b3e7dab5 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -9775,6 +9775,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, return ''; }, brokenConnection530Error: 'Recibo pendente devido à conexão bancária interrompida', + brokenConnection531Error: 'Recibo pendente devido a um problema temporário no banco. Tente novamente mais tarde.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Recibo pendente devido a uma conexão bancária interrompida. Resolva em Cartões corporativos.`, memberBrokenConnectionError: 'Recibo pendente devido à conexão bancária com problemas. Peça a um administrador do workspace para resolver.', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 283097d61a33..00123154163b 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -9432,6 +9432,7 @@ ${reportName}`, return ''; }, brokenConnection530Error: '由于银行连接中断,收据待处理', + brokenConnection531Error: '由于银行出现暂时性问题,收据待处理。请稍后重试。', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `由于银行连接中断,收据暂时待处理。请前往公司卡中解决。`, memberBrokenConnectionError: '由于银行连接中断,收据处于待处理状态。请联系工作区管理员解决。', diff --git a/tests/ui/BrokenConnectionDescriptionTest.tsx b/tests/ui/BrokenConnectionDescriptionTest.tsx new file mode 100644 index 000000000000..8e690a222b94 --- /dev/null +++ b/tests/ui/BrokenConnectionDescriptionTest.tsx @@ -0,0 +1,63 @@ +import {render, screen} from '@testing-library/react-native'; + +import BrokenConnectionDescription from '@components/BrokenConnectionDescription'; +import ComposeProviders from '@components/ComposeProviders'; +import HTMLEngineProvider from '@components/HTMLEngineProvider'; +import {LocaleContextProvider} from '@components/LocaleContextProvider'; +import OnyxListItemProvider from '@components/OnyxListItemProvider'; + +import CONST from '@src/CONST'; +import IntlStore from '@src/languages/IntlStore'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {TransactionViolations} from '@src/types/onyx'; + +import React from 'react'; +import {Text} from 'react-native'; +import Onyx from 'react-native-onyx'; + +import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; + +const mockUseTransactionViolations = jest.fn(); +jest.mock('@hooks/useTransactionViolations', () => ({ + __esModule: true, + default: (...args: unknown[]) => mockUseTransactionViolations(...args), +})); + +const renderDescription = () => + render( + + + + + , + ); + +describe('BrokenConnectionDescription', () => { + beforeAll(() => { + Onyx.init({keys: ONYXKEYS}); + return IntlStore.load(CONST.LOCALES.EN); + }); + + afterEach(() => { + mockUseTransactionViolations.mockReset(); + }); + + it('shows the temporary retry-later message for a 531 broken card connection', async () => { + mockUseTransactionViolations.mockReturnValue([ + { + name: 'rter', + type: 'violation', + data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531}, + }, + ] as TransactionViolations); + + renderDescription(); + await waitForBatchedUpdatesWithAct(); + + expect(screen.getByText('Receipt pending due to a temporary bank issue. Please try again later.')).toBeTruthy(); + }); +}); From 26e5b2cdf84c8f3dc2db2e9cf385eccf153542fb Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Fri, 14 Aug 2026 13:58:34 -0600 Subject: [PATCH 2/4] Handle brokenCardConnection531 in the rter violation translation The main expense violation message comes from the violations.rter translation (via ViolationsUtils.getViolationTranslation), not only from BrokenConnectionDescription. Add a 531 branch there in every language so the temporary retry-later copy shows instead of falling through to the wrong message, and cover it with a getViolationTranslation unit test. --- src/languages/de.ts | 3 +++ src/languages/el.ts | 3 +++ src/languages/en.ts | 3 +++ src/languages/es.ts | 3 +++ src/languages/fr.ts | 3 +++ src/languages/it.ts | 3 +++ src/languages/ja.ts | 3 +++ src/languages/nl.ts | 3 +++ src/languages/pl.ts | 3 +++ src/languages/pt-BR.ts | 3 +++ src/languages/zh-hans.ts | 3 +++ tests/unit/ViolationUtilsTest.ts | 16 ++++++++++++++++ 12 files changed, 49 insertions(+) diff --git a/src/languages/de.ts b/src/languages/de.ts index 27c5dfbd0499..03afddcdaafe 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -9818,6 +9818,9 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'Beleg kann wegen unterbrochener Bankverbindung nicht automatisch zugeordnet werden.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'Beleg kann wegen eines vorübergehenden Bankproblems nicht automatisch zugeordnet werden. Bitte versuchen Sie es später erneut.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'Beleg kann wegen unterbrochener Bankverbindung nicht automatisch zugeordnet werden.'; diff --git a/src/languages/el.ts b/src/languages/el.ts index 37930e7fb8f8..26ca9ad94984 100644 --- a/src/languages/el.ts +++ b/src/languages/el.ts @@ -10049,6 +10049,9 @@ ${reportName}`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'Δεν είναι δυνατή η αυτόματη αντιστοίχιση της απόδειξης λόγω σπασμένης σύνδεσης με την τράπεζα.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'Δεν είναι δυνατή η αυτόματη αντιστοίχιση της απόδειξης λόγω προσωρινού προβλήματος της τράπεζας. Δοκιμάστε ξανά αργότερα.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'Δεν είναι δυνατή η αυτόματη αντιστοίχιση της απόδειξης λόγω σπασμένης σύνδεσης με την τράπεζα.'; diff --git a/src/languages/en.ts b/src/languages/en.ts index 6b80decf849c..0c8dbaa384eb 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -9961,6 +9961,9 @@ const translations = { if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return "Can't auto-match receipt due to broken bank connection."; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return "Can't auto-match receipt due to a temporary bank issue. Please try again later."; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return "Can't auto-match receipt due to broken bank connection."; diff --git a/src/languages/es.ts b/src/languages/es.ts index d89194f7af21..39adbad691ed 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -10019,6 +10019,9 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'No se puede emparejar automáticamente el recibo debido a una conexión bancaria interrumpida.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'No se puede emparejar automáticamente el recibo debido a un problema temporal del banco. Vuelve a intentarlo más tarde.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'No se puede emparejar automáticamente el recibo debido a una conexión bancaria interrumpida.'; diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 27034eae1c38..81a82b913367 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -9854,6 +9854,9 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'Impossible d’apparier automatiquement le reçu en raison d’une connexion bancaire rompue.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'Impossible d’apparier automatiquement le reçu en raison d’un problème temporaire de la banque. Veuillez réessayer plus tard.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'Impossible d’apparier automatiquement le reçu en raison d’une connexion bancaire rompue.'; diff --git a/src/languages/it.ts b/src/languages/it.ts index 23222d87743a..8e90d7ec66f0 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -9791,6 +9791,9 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'Impossibile abbinare automaticamente la ricevuta a causa di un problema di connessione bancaria.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'Impossibile abbinare automaticamente la ricevuta a causa di un problema temporaneo della banca. Riprova più tardi.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'Impossibile abbinare automaticamente la ricevuta a causa di un problema di connessione bancaria.'; diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 7f2133781632..4e3eac48d699 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -9662,6 +9662,9 @@ ${reportName}`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return '銀行連携の不具合により、領収書を自動照合できません。'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return '銀行側の一時的な問題により、領収書を自動照合できません。後でもう一度お試しください。'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return '銀行連携の不具合により、領収書を自動照合できません。'; diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 788872ddaae9..b09e72f3f7bd 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -9761,6 +9761,9 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'Bon kan automatisch aan bon koppelen vanwege verbroken bankverbinding.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'Bon kan niet automatisch worden gekoppeld vanwege een tijdelijk probleem bij de bank. Probeer het later opnieuw.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'Bon kan automatisch aan bon koppelen vanwege verbroken bankverbinding.'; diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 9f7a8df0ec1f..ec866de3bf34 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -9733,6 +9733,9 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'Nie można automatycznie dopasować paragonu z powodu zerwanego połączenia z bankiem.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'Nie można automatycznie dopasować paragonu z powodu tymczasowego problemu z bankiem. Spróbuj ponownie później.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'Nie można automatycznie dopasować paragonu z powodu zerwanego połączenia z bankiem.'; diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 85e2b3e7dab5..b5388096e00c 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -9756,6 +9756,9 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return 'Não é possível conciliar automaticamente o recibo devido a uma conexão bancária com erro.'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return 'Não é possível conciliar automaticamente o recibo devido a um problema temporário no banco. Tente novamente mais tarde.'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return 'Não é possível conciliar automaticamente o recibo devido a uma conexão bancária com erro.'; diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 00123154163b..f20faa0e2729 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -9415,6 +9415,9 @@ ${reportName}`, if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) { return '由于银行连接中断,无法自动匹配收据。'; } + if (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) { + return '由于银行出现暂时性问题,无法自动匹配收据。请稍后重试。'; + } if (isPersonalCard && (rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || brokenBankConnection)) { if (!connectionLink) { return '由于银行连接中断,无法自动匹配收据。'; diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index 1e7cf440f632..fc3182c88bee 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -3421,6 +3421,14 @@ const brokenCardConnection530Violation: TransactionViolation = { }, }; +const brokenCardConnection531Violation: TransactionViolation = { + name: CONST.VIOLATIONS.RTER, + type: CONST.VIOLATION_TYPES.VIOLATION, + data: { + rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531, + }, +}; + describe('getViolationTranslation', () => { it('should return the correct message for broken card connection violation', () => { const testPolicyID = 'test-policy-123'; @@ -3443,6 +3451,14 @@ describe('getViolationTranslation', () => { ); }); + it('should return the temporary retry-later message for a 531 broken card connection', async () => { + IntlStore.load(CONST.LOCALES.EN); + await waitForBatchedUpdates(); + expect(ViolationsUtils.getViolationTranslation({dateFnsLocale: undefined, violation: brokenCardConnection531Violation, translate: translateLocal, convertToDisplayString})).toBe( + "Can't auto-match receipt due to a temporary bank issue. Please try again later.", + ); + }); + describe('increasedDistance violation', () => { const increasedDistanceViolation: TransactionViolation = { name: CONST.VIOLATIONS.INCREASED_DISTANCE, From 0f37a436db12429feecef6c8b99f21865c67c67d Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Fri, 14 Aug 2026 14:19:09 -0600 Subject: [PATCH 3/4] Align 531 copy across both violation surfaces Use the same 'Can't auto-match receipt due to a temporary bank issue. Please try again later.' wording for both the rter violation message and the brokenConnection531Error header copy, so the two surfaces show one consistent message. --- src/languages/de.ts | 2 +- src/languages/el.ts | 2 +- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/languages/fr.ts | 2 +- src/languages/it.ts | 2 +- src/languages/ja.ts | 2 +- src/languages/nl.ts | 2 +- src/languages/pl.ts | 2 +- src/languages/pt-BR.ts | 2 +- src/languages/zh-hans.ts | 2 +- tests/ui/BrokenConnectionDescriptionTest.tsx | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/languages/de.ts b/src/languages/de.ts index 03afddcdaafe..a66bf9000915 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -9840,7 +9840,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc return ''; }, brokenConnection530Error: 'Beleg ausstehend wegen unterbrochener Bankverbindung', - brokenConnection531Error: 'Beleg ausstehend aufgrund eines vorübergehenden Bankproblems. Bitte versuchen Sie es später erneut.', + brokenConnection531Error: 'Beleg kann wegen eines vorübergehenden Bankproblems nicht automatisch zugeordnet werden. Bitte versuchen Sie es später erneut.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Beleg ausstehend wegen unterbrochener Bankverbindung. Bitte in Firmenkarten beheben.`, memberBrokenConnectionError: 'Beleg ausstehend aufgrund einer unterbrochenen Bankverbindung. Bitte wende dich an eine Workspace-Admin, um das Problem zu beheben.', diff --git a/src/languages/el.ts b/src/languages/el.ts index 26ca9ad94984..ebc0c6056179 100644 --- a/src/languages/el.ts +++ b/src/languages/el.ts @@ -10071,7 +10071,7 @@ ${reportName}`, return ''; }, brokenConnection530Error: 'Η απόδειξη εκκρεμεί λόγω αποσυνδεδεμένου τραπεζικού λογαριασμού', - brokenConnection531Error: 'Η απόδειξη εκκρεμεί λόγω προσωρινού προβλήματος της τράπεζας. Δοκιμάστε ξανά αργότερα.', + brokenConnection531Error: 'Δεν είναι δυνατή η αυτόματη αντιστοίχιση της απόδειξης λόγω προσωρινού προβλήματος της τράπεζας. Δοκιμάστε ξανά αργότερα.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Η απόδειξη εκκρεμεί λόγω κατεστραμμένης σύνδεσης τράπεζας. Παρακαλώ επιλύστε το στις εταιρικές κάρτες.`, memberBrokenConnectionError: 'Η απόδειξη εκκρεμεί λόγω προβλήματος στη σύνδεση με την τράπεζα. Παρακαλείστε να ζητήσετε από έναν διαχειριστή χώρου εργασίας να το επιλύσει.', diff --git a/src/languages/en.ts b/src/languages/en.ts index 0c8dbaa384eb..325e78b764f9 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -9984,7 +9984,7 @@ const translations = { return ''; }, brokenConnection530Error: 'Receipt pending due to broken bank connection', - brokenConnection531Error: 'Receipt pending due to a temporary bank issue. Please try again later.', + brokenConnection531Error: "Can't auto-match receipt due to a temporary bank issue. Please try again later.", adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Receipt pending due to broken bank connection. Please resolve in Company cards.`, memberBrokenConnectionError: 'Receipt pending due to broken bank connection. Please ask a workspace admin to resolve.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 39adbad691ed..5edf0174a2ad 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -10043,7 +10043,7 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`, return ''; }, brokenConnection530Error: 'Recibo pendiente debido a una conexión bancaria rota', - brokenConnection531Error: 'Recibo pendiente debido a un problema temporal del banco. Vuelve a intentarlo más tarde.', + brokenConnection531Error: 'No se puede emparejar automáticamente el recibo debido a un problema temporal del banco. Vuelve a intentarlo más tarde.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}) => `Recibo pendiente debido a una conexión bancaria rota. Por favor, resuélvelo en Tarjetas de empresa.`, memberBrokenConnectionError: 'Recibo pendiente debido a una conexión bancaria rota. Por favor, pide a un administrador del espacio de trabajo que lo resuelva.', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 81a82b913367..5b81514bff86 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -9876,7 +9876,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e return ''; }, brokenConnection530Error: 'Reçu en attente en raison d’une connexion bancaire rompue', - brokenConnection531Error: 'Reçu en attente en raison d’un problème temporaire de la banque. Veuillez réessayer plus tard.', + brokenConnection531Error: 'Impossible d’apparier automatiquement le reçu en raison d’un problème temporaire de la banque. Veuillez réessayer plus tard.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Reçu en attente en raison d’une connexion bancaire rompue. Veuillez résoudre le problème dans les Cartes d’entreprise.`, memberBrokenConnectionError: 'Reçu en attente en raison d’une connexion bancaire rompue. Veuillez demander à un administrateur de l’espace de travail de résoudre le problème.', diff --git a/src/languages/it.ts b/src/languages/it.ts index 8e90d7ec66f0..0eb14ea3ecd1 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -9813,7 +9813,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`, return ''; }, brokenConnection530Error: 'Ricevuta in sospeso a causa di connessione bancaria interrotta', - brokenConnection531Error: 'Ricevuta in sospeso a causa di un problema temporaneo della banca. Riprova più tardi.', + brokenConnection531Error: 'Impossibile abbinare automaticamente la ricevuta a causa di un problema temporaneo della banca. Riprova più tardi.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Ricevuta in sospeso a causa di un collegamento bancario interrotto. Risolvi il problema in Carte aziendali.`, memberBrokenConnectionError: 'Ricevuta in sospeso a causa di un collegamento bancario interrotto. Chiedi a un amministratore dello spazio di lavoro di risolvere il problema.', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 4e3eac48d699..b09fb6a827b0 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -9684,7 +9684,7 @@ ${reportName}`, return ''; }, brokenConnection530Error: '銀行連携の不具合により領収書が保留されています', - brokenConnection531Error: '銀行側の一時的な問題により領収書が保留されています。後でもう一度お試しください。', + brokenConnection531Error: '銀行側の一時的な問題により、領収書を自動照合できません。後でもう一度お試しください。', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `銀行接続の不具合により領収書が保留されています。会社カードで解決してください。`, memberBrokenConnectionError: '銀行連携の不具合により領収書が保留されています。ワークスペース管理者に対応を依頼してください。', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index b09e72f3f7bd..f2b65c8492e4 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -9783,7 +9783,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`, return ''; }, brokenConnection530Error: 'Bonnetje in behandeling vanwege verbroken bankverbinding', - brokenConnection531Error: 'Bonnetje in behandeling vanwege een tijdelijk probleem bij de bank. Probeer het later opnieuw.', + brokenConnection531Error: 'Bon kan niet automatisch worden gekoppeld vanwege een tijdelijk probleem bij de bank. Probeer het later opnieuw.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Bon in behandeling vanwege een verbroken bankverbinding. Los dit op in Bedrijfspassen.`, memberBrokenConnectionError: 'Bon wordt vastgehouden vanwege een verbroken bankkoppeling. Vraag een werkruimtebeheerder om dit op te lossen.', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index ec866de3bf34..10ab61d5497b 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -9755,7 +9755,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`, return ''; }, brokenConnection530Error: 'Paragon oczekuje z powodu przerwanego połączenia z bankiem', - brokenConnection531Error: 'Paragon oczekuje z powodu tymczasowego problemu z bankiem. Spróbuj ponownie później.', + brokenConnection531Error: 'Nie można automatycznie dopasować paragonu z powodu tymczasowego problemu z bankiem. Spróbuj ponownie później.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Oczekuje na rachunek z powodu przerwanego połączenia z bankiem. Rozwiąż problem w sekcji Karty firmowe.`, memberBrokenConnectionError: 'Paragon oczekuje z powodu zerwanego połączenia z bankiem. Poproś administratora przestrzeni roboczej o rozwiązanie problemu.', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index b5388096e00c..07715659c176 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -9778,7 +9778,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, return ''; }, brokenConnection530Error: 'Recibo pendente devido à conexão bancária interrompida', - brokenConnection531Error: 'Recibo pendente devido a um problema temporário no banco. Tente novamente mais tarde.', + brokenConnection531Error: 'Não é possível conciliar automaticamente o recibo devido a um problema temporário no banco. Tente novamente mais tarde.', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `Recibo pendente devido a uma conexão bancária interrompida. Resolva em Cartões corporativos.`, memberBrokenConnectionError: 'Recibo pendente devido à conexão bancária com problemas. Peça a um administrador do workspace para resolver.', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index f20faa0e2729..6c714aa40826 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -9435,7 +9435,7 @@ ${reportName}`, return ''; }, brokenConnection530Error: '由于银行连接中断,收据待处理', - brokenConnection531Error: '由于银行出现暂时性问题,收据待处理。请稍后重试。', + brokenConnection531Error: '由于银行出现暂时性问题,无法自动匹配收据。请稍后重试。', adminBrokenConnectionError: ({workspaceCompanyCardRoute}: {workspaceCompanyCardRoute: string}) => `由于银行连接中断,收据暂时待处理。请前往公司卡中解决。`, memberBrokenConnectionError: '由于银行连接中断,收据处于待处理状态。请联系工作区管理员解决。', diff --git a/tests/ui/BrokenConnectionDescriptionTest.tsx b/tests/ui/BrokenConnectionDescriptionTest.tsx index 8e690a222b94..5acadb199f58 100644 --- a/tests/ui/BrokenConnectionDescriptionTest.tsx +++ b/tests/ui/BrokenConnectionDescriptionTest.tsx @@ -58,6 +58,6 @@ describe('BrokenConnectionDescription', () => { renderDescription(); await waitForBatchedUpdatesWithAct(); - expect(screen.getByText('Receipt pending due to a temporary bank issue. Please try again later.')).toBeTruthy(); + expect(screen.getByText("Can't auto-match receipt due to a temporary bank issue. Please try again later.")).toBeTruthy(); }); }); From 4456a9f54335118901fa64c444e6766183351d61 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Fri, 14 Aug 2026 14:32:01 -0600 Subject: [PATCH 4/4] Classify 531 as a broken connection, not a pending RTER 531 was missing from the broken-connection classifiers, so a 531 violation was treated as a generic pending RTER (showing 'Awaiting merge with card transaction.') instead of a broken connection. Add 531 alongside 530 in isBrokenConnectionViolation and hasPendingRTERViolation, and in the MoneyRequestHeader and report status bar broken-connection lookups, so shouldShowBrokenConnectionViolation is true and the 531 copy shows. Covered by a shouldShowBrokenConnectionViolation unit test. --- src/components/MoneyRequestHeader.tsx | 5 ++++- src/hooks/useMoneyReportHeaderStatusBar.ts | 5 ++++- src/libs/TransactionUtils/index.ts | 7 +++++-- tests/unit/TransactionUtilsTest.ts | 8 ++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index 0dadca3f4edf..849f83d886c2 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -128,7 +128,10 @@ function MoneyRequestHeader({reportID: reportIDProp, onBackButtonPress}: MoneyRe return {icon: getStatusIcon(icons.CreditCardHourglass), description: translate('iou.transactionPendingDescription')}; } if (!!transaction?.transactionID && !!transactionViolations.length && shouldShowBrokenConnectionViolation) { - const brokenConnectionError = transactionViolations?.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION); + const brokenConnectionError = transactionViolations?.find( + (violation) => + violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531, + ); const cardID = brokenConnectionError?.data?.cardID; const card = cardID ? cardList?.[cardID] : undefined; const isBrokenPersonalCard = isPersonalCard(card); diff --git a/src/hooks/useMoneyReportHeaderStatusBar.ts b/src/hooks/useMoneyReportHeaderStatusBar.ts index 2f45d7a3d185..1e2bd3bfa61f 100644 --- a/src/hooks/useMoneyReportHeaderStatusBar.ts +++ b/src/hooks/useMoneyReportHeaderStatusBar.ts @@ -122,7 +122,10 @@ function useMoneyReportHeaderStatusBar(reportID: string | undefined, chatReportI return CONST.REPORT.STATUS_BAR_TYPE.DUPLICATES; } if (!!transaction?.transactionID && !!transactionViolations.length && shouldShowBrokenConnectionViolation) { - const brokenConnectionError = transactionViolations.find((violation) => violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION); + const brokenConnectionError = transactionViolations.find( + (violation) => + violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531, + ); const cardID = brokenConnectionError?.data?.cardID; const card = cardID ? cardList?.[cardID] : undefined; if (isPersonalCard(card) && brokenConnectionError) { diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index 9be380e29052..2335b96564ab 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -1862,7 +1862,8 @@ function hasPendingRTERViolation(transactionViolations?: TransactionViolations | transactionViolation.name === CONST.VIOLATIONS.RTER && transactionViolation.data?.pendingPattern && transactionViolation.data?.rterType !== CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION && - transactionViolation.data?.rterType !== CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530, + transactionViolation.data?.rterType !== CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 && + transactionViolation.data?.rterType !== CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531, ); } @@ -1910,7 +1911,9 @@ function hasBrokenConnectionViolation( function isBrokenConnectionViolation(violation: TransactionViolation) { return ( violation.name === CONST.VIOLATIONS.RTER && - (violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530) + (violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION || + violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_530 || + violation.data?.rterType === CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531) ); } diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index 865ea3d412fe..04864f31bcb8 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -1293,6 +1293,14 @@ describe('TransactionUtils', () => { expect(showBrokenConnectionViolation).toBe(true); }); + it('should return true for a 531 (temporary, retry later) broken connection violation', () => { + const policy = createMock({role: CONST.POLICY.ROLE.USER}); + const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER, data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION_531}}]; + const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(undefined, policy, transactionViolations); + + expect(showBrokenConnectionViolation).toBe(true); + }); + it('should return true when a broken connection violation exists for any of the provided transactions and the user is the policy member', () => { const policy = createMock({ role: CONST.POLICY.ROLE.USER,