Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8021,6 +8021,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
personalCard: 'Private Karte',
companyCard: 'Firmenkarte',
expensifyCard: 'Expensify Karte',
centralInvoicing: 'Zentrale Rechnungsstellung',
},
distance: {
addStop: 'Stopp hinzufügen',
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7981,6 +7981,7 @@ const translations = {
personalCard: 'Personal card',
companyCard: 'Company card',
expensifyCard: 'Expensify Card',
centralInvoicing: 'Central invoicing',
},
distance: {
addStop: 'Add stop',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8297,6 +8297,7 @@ ${amount} para ${merchant} - ${date}`,
personalCard: 'Tarjeta personal',
companyCard: 'Tarjeta corporativa',
expensifyCard: 'Tarjeta Expensify',
centralInvoicing: 'Facturación centralizada',
},
distance: {
addStop: 'Añadir parada',
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8044,6 +8044,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
personalCard: 'Carte personnelle',
companyCard: 'Carte d’entreprise',
expensifyCard: 'Carte Expensify',
centralInvoicing: 'Facturation centralisée',
},
distance: {
addStop: 'Ajouter un arrêt',
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8010,6 +8010,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
personalCard: 'Carta personale',
companyCard: 'Carta aziendale',
expensifyCard: 'Carta Expensify',
centralInvoicing: 'Fatturazione centralizzata',
},
distance: {
addStop: 'Aggiungi fermata',
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7912,6 +7912,7 @@ ${reportName}
personalCard: '個人のカード',
companyCard: '会社カード',
expensifyCard: 'Expensify カード',
centralInvoicing: '集中請求',
},
distance: {
addStop: '経由地を追加',
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7987,6 +7987,7 @@ Voeg meer bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
personalCard: 'Persoonlijke kaart',
companyCard: 'Bedrijfskaart',
expensifyCard: 'Expensify Kaart',
centralInvoicing: 'Gecentraliseerde facturatie',
},
distance: {
addStop: 'Stop toevoegen',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7976,6 +7976,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
personalCard: 'Karta osobista',
companyCard: 'Karta firmowa',
expensifyCard: 'Karta Expensify',
centralInvoicing: 'Centralne fakturowanie',
},
distance: {
addStop: 'Dodaj przystanek',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7980,6 +7980,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
personalCard: 'Cartão pessoal',
companyCard: 'Cartão corporativo',
expensifyCard: 'Cartão Expensify',
centralInvoicing: 'Faturamento centralizado',
},
distance: {
addStop: 'Adicionar parada',
Expand Down
10 changes: 9 additions & 1 deletion src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7763,7 +7763,15 @@ ${reportName}
tryDifferentEmail: '请尝试使用其他邮箱',
},
},
cardTransactions: {notActivated: '未激活', outOfPocket: '可报销', companySpend: '不可报销', personalCard: '个人银行卡', companyCard: '公司卡', expensifyCard: 'Expensify 卡'},
cardTransactions: {
notActivated: '未激活',
outOfPocket: '可报销',
companySpend: '不可报销',
personalCard: '个人银行卡',
companyCard: '公司卡',
expensifyCard: 'Expensify 卡',
centralInvoicing: '集中开票',
},
distance: {
addStop: '添加站点',
address: '地址',
Expand Down
9 changes: 6 additions & 3 deletions src/libs/CardUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ function getCardDescription(card: Card | undefined, translate: LocalizedTranslat
if (!card) {
return '';
}
if (isTravelCard(card)) {
return translate('cardTransactions.centralInvoicing');
}
const isCSVCard = card.bank === CONST.COMPANY_CARD.FEED_BANK_NAME.UPLOAD || card.bank?.includes(CONST.COMPANY_CARD.FEED_BANK_NAME.CSV);
if (isCSVCard) {
return card.nameValuePairs?.cardTitle ?? card.cardName ?? '';
Expand All @@ -180,9 +183,9 @@ function getCardDescription(card: Card | undefined, translate: LocalizedTranslat
* @param displayName
* @returns string in format %<defaultOrCustomCardName> • <lastFourPAN>%.
*/
function getCardDescriptionForSearchTable(card?: Card, displayName?: string) {
if (!card) {
return '';
function getCardDescriptionForSearchTable(card: Card, translate: LocalizedTranslate, displayName?: string) {
if (isTravelCard(card)) {
return translate('cardTransactions.centralInvoicing');
}
const isCSVCard = card.bank === CONST.COMPANY_CARD.FEED_BANK_NAME.UPLOAD || card.bank?.includes(CONST.COMPANY_CARD.FEED_BANK_NAME.CSV);
if (isCSVCard) {
Expand Down
1 change: 1 addition & 0 deletions src/libs/SearchUIUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2774,6 +2774,7 @@ function getCardSections(
cardName: cardGroup.cardName,
lastFourPAN: cardGroup.lastFourPAN,
} as OnyxTypes.Card,
translate,
personalDetails?.displayName,
);
cardDescriptionByCardID.set(cardGroup.cardID, formattedCardName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function SpendRulePageBase({policyID, titleKey, testID}: SpendRulePageBaseProps)
}
const accountID = card.accountID ?? CONST.DEFAULT_NUMBER_ID;
const displayName = getDisplayNameOrDefault(personalDetails?.[accountID], '', false);
return getCardDescriptionForSearchTable(card, displayName || undefined) || id;
return getCardDescriptionForSearchTable(card, translate, displayName || undefined) || id;
}),
(summary, count) => translate('workspace.rules.spendRules.summaryMoreCount', {summary, count}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ function SpendRulesSection({policyID}: SpendRulesSectionProps) {

const accountID = card.accountID ?? CONST.DEFAULT_NUMBER_ID;
const displayName = getDisplayNameOrDefault(personalDetails?.[accountID], '', false);
return getCardDescriptionForSearchTable(card, displayName || undefined) || cardID;
return getCardDescriptionForSearchTable(card, translate, displayName || undefined) || cardID;
}),
(summary, count) => translate('workspace.rules.spendRules.summaryMoreCount', {summary, count}),
);
Expand Down
60 changes: 60 additions & 0 deletions tests/unit/CardUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getBankName,
getBrokenConnectionUrlToFixPersonalCard,
getCardDescription,
getCardDescriptionForSearchTable,
getCardFeedIcon,
getCardFeedWithDomainID,
getCardHintText,
Expand Down Expand Up @@ -2271,6 +2272,26 @@ describe('CardUtils', () => {
expect(description).toBe(CONST.EXPENSIFY_CARD.BANK);
});

it('should return Central invoicing for travel invoicing cards', () => {
const card: Card = {
accountID: 18439984,
bank: CONST.EXPENSIFY_CARD.BANK,
cardID: 21570657,
cardName: 'CREDIT CARD...6909',
domainName: 'expensify-policy17f617b9fe23d2f1.exfy',
fraud: 'none',
lastFourPAN: '6909',
lastScrape: '',
lastUpdated: '',
state: 3,
nameValuePairs: {
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
} as Card['nameValuePairs'],
};
const description = getCardDescription(card, translateLocal);
expect(description).toBe('Central invoicing');
});

it('should return the correct card description for personal card', () => {
const personalCard: Card = {
accountID: 1,
Expand All @@ -2289,6 +2310,45 @@ describe('CardUtils', () => {
});
});

describe('getCardDescriptionForSearchTable', () => {
it('should return Central invoicing for travel invoicing cards when translate is provided', () => {
const card: Card = {
accountID: 18439984,
bank: CONST.EXPENSIFY_CARD.BANK,
cardID: 21570657,
cardName: 'CREDIT CARD...6909',
domainName: 'expensify-policy17f617b9fe23d2f1.exfy',
fraud: 'none',
lastFourPAN: '6909',
lastScrape: '',
lastUpdated: '',
state: 3,
nameValuePairs: {
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
} as Card['nameValuePairs'],
};
const description = getCardDescriptionForSearchTable(card, translateLocal, 'John Doe');
expect(description).toBe('Central invoicing');
});

it('should return normal description for non-travel Expensify cards', () => {
const card: Card = {
accountID: 18439984,
bank: CONST.EXPENSIFY_CARD.BANK,
cardID: 21570657,
cardName: 'Expensify Card',
domainName: 'expensify-policy17f617b9fe23d2f1.exfy',
fraud: 'none',
lastFourPAN: '5644',
lastScrape: '',
lastUpdated: '',
state: 3,
};
const description = getCardDescriptionForSearchTable(card, translateLocal, 'John Doe');
expect(description).toBe("John Doe's card • 5644");
});
});

describe('getDisplayableExpensifyCards', () => {
it('should return empty array when cardList is undefined', () => {
const result = getDisplayableExpensifyCards(undefined);
Expand Down
16 changes: 6 additions & 10 deletions tests/unit/Search/SearchUIUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8715,10 +8715,6 @@ describe('getCardDescriptionForSearchTable', () => {
state: 3,
};

it('returns an empty string when card is undefined', () => {
expect(getCardDescriptionForSearchTable(undefined)).toBe('');
});

it('returns CSV/upload card title from nameValuePairs for UPLOAD bank', () => {
const card: OnyxTypes.Card = {
...baseCompanyCard,
Expand All @@ -8727,7 +8723,7 @@ describe('getCardDescriptionForSearchTable', () => {
cardTitle: 'Uploaded spend card',
} as OnyxTypes.Card['nameValuePairs'],
};
expect(getCardDescriptionForSearchTable(card)).toBe('Uploaded spend card');
expect(getCardDescriptionForSearchTable(card, translateLocal)).toBe('Uploaded spend card');
});

it('returns CSV card title when bank is CSV feed', () => {
Expand All @@ -8739,7 +8735,7 @@ describe('getCardDescriptionForSearchTable', () => {
cardTitle: 'Marketing Team Card',
} as OnyxTypes.Card['nameValuePairs'],
};
expect(getCardDescriptionForSearchTable(card)).toBe('Marketing Team Card');
expect(getCardDescriptionForSearchTable(card, translateLocal)).toBe('Marketing Team Card');
});

it('falls back to cardName for CSV/upload when cardTitle is missing', () => {
Expand All @@ -8748,22 +8744,22 @@ describe('getCardDescriptionForSearchTable', () => {
bank: CONST.COMPANY_CARD.FEED_BANK_NAME.CSV,
cardName: 'Fallback CSV label',
};
expect(getCardDescriptionForSearchTable(card)).toBe('Fallback CSV label');
expect(getCardDescriptionForSearchTable(card, translateLocal)).toBe('Fallback CSV label');
});

it('returns default cardholder label and last four for non-CSV cards when displayName is provided', () => {
expect(getCardDescriptionForSearchTable(baseCompanyCard, 'Jane')).toBe(`Jane's card ${CONST.DOT_SEPARATOR} 2554`);
expect(getCardDescriptionForSearchTable(baseCompanyCard, translateLocal, 'Jane')).toBe(`Jane's card ${CONST.DOT_SEPARATOR} 2554`);
});

it('omits the dot separator when lastFourPAN is empty', () => {
const card: OnyxTypes.Card = {
...baseCompanyCard,
lastFourPAN: '',
};
expect(getCardDescriptionForSearchTable(card, 'Jane')).toBe(`Jane's card`);
expect(getCardDescriptionForSearchTable(card, translateLocal, 'Jane')).toBe(`Jane's card`);
});

it('uses only last four with leading separator when displayName is missing (search table card group shape)', () => {
expect(getCardDescriptionForSearchTable(baseCompanyCard)).toBe(` ${CONST.DOT_SEPARATOR} 2554`);
expect(getCardDescriptionForSearchTable(baseCompanyCard, translateLocal)).toBe(` ${CONST.DOT_SEPARATOR} 2554`);
});
});
Loading